diff --git a/.gitignore b/.gitignore index 7acc86ceb..3cde66362 100644 --- a/.gitignore +++ b/.gitignore @@ -336,3 +336,5 @@ input/EUROMODoutput/current/uk_2024_std.txt input/EUROMODoutput/current/uk_2025_std.txt input/EUROMODoutput/current/uk_2026_std.txt input/EUROMODoutput/current/uk_2027_std.txt +input/tax_donor_population_HU.csv +input/tax_donor_population_PL.csv diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/config/default.yml b/config/default.yml index 4f3afba82..1b25c792a 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1,11 +1,11 @@ # This file can be used to override defaults for multirun arguments. # Arguments of the SimPathsMultiRun object overridden by the command-line -maxNumberOfRuns: 1 +maxNumberOfRuns: 3 executeWithGui: false randomSeed: 606 -startYear: 2019 -endYear: 2026 +startYear: 2011 +endYear: 2025 popSize: 170000 # Arguments passed to the SimPathsModel diff --git a/input/DatabaseCountryYear.xlsx b/input/DatabaseCountryYear.xlsx index b8dc7597b..795e5baa4 100644 Binary files a/input/DatabaseCountryYear.xlsx and b/input/DatabaseCountryYear.xlsx differ diff --git a/input/EUROMODpolicySchedule.xlsx b/input/EUROMODpolicySchedule.xlsx index 72ca67946..6b8bd6675 100644 Binary files a/input/EUROMODpolicySchedule.xlsx and b/input/EUROMODpolicySchedule.xlsx differ diff --git a/input/align_educLevel.xlsx b/input/align_educLevel.xlsx index a1fa199fc..cd37db4b2 100644 Binary files a/input/align_educLevel.xlsx and b/input/align_educLevel.xlsx differ diff --git a/input/align_popProjections.xlsx b/input/align_popProjections.xlsx index 2abf8035d..2569adb7e 100644 Binary files a/input/align_popProjections.xlsx and b/input/align_popProjections.xlsx differ diff --git a/input/align_student_under30.xlsx b/input/align_student_under30.xlsx index efcf613b7..18ed1dfdf 100644 Binary files a/input/align_student_under30.xlsx and b/input/align_student_under30.xlsx differ diff --git a/input/policy parameters.xlsx b/input/policy parameters.xlsx index 5e64540b5..5bcf7547f 100644 Binary files a/input/policy parameters.xlsx and b/input/policy parameters.xlsx differ diff --git a/input/projections_fertility.xlsx b/input/projections_fertility.xlsx index cf5365fa3..1a94b5c04 100644 Binary files a/input/projections_fertility.xlsx and b/input/projections_fertility.xlsx differ diff --git a/input/projections_mortality.xlsx b/input/projections_mortality.xlsx index 5a65dccfd..89741a2b3 100644 Binary files a/input/projections_mortality.xlsx and b/input/projections_mortality.xlsx differ diff --git a/input/reg_RMSE.xlsx b/input/reg_RMSE.xlsx index 8d9d984a4..ff1367c3c 100644 Binary files a/input/reg_RMSE.xlsx and b/input/reg_RMSE.xlsx differ diff --git a/input/reg_education.xlsx b/input/reg_education.xlsx index c4c96c2c4..3bfad3479 100644 Binary files a/input/reg_education.xlsx and b/input/reg_education.xlsx differ diff --git a/input/reg_employmentSelection.xlsx b/input/reg_employmentSelection.xlsx index e3734b6ac..2f0842180 100644 Binary files a/input/reg_employmentSelection.xlsx and b/input/reg_employmentSelection.xlsx differ diff --git a/input/reg_fertility.xlsx b/input/reg_fertility.xlsx index f9dac777c..7294aebbc 100644 Binary files a/input/reg_fertility.xlsx and b/input/reg_fertility.xlsx differ diff --git a/input/reg_health.xlsx b/input/reg_health.xlsx index 74994f26e..6df12ca53 100644 Binary files a/input/reg_health.xlsx and b/input/reg_health.xlsx differ diff --git a/input/reg_home_ownership.xlsx b/input/reg_home_ownership.xlsx index 4803ba8a7..b5e5cbc8f 100644 Binary files a/input/reg_home_ownership.xlsx and b/input/reg_home_ownership.xlsx differ diff --git a/input/reg_income.xlsx b/input/reg_income.xlsx index f10d898aa..400fd8aa1 100644 Binary files a/input/reg_income.xlsx and b/input/reg_income.xlsx differ diff --git a/input/reg_labourSupplyUtility.xlsx b/input/reg_labourSupplyUtility.xlsx index db48d381d..380acc9c4 100644 Binary files a/input/reg_labourSupplyUtility.xlsx and b/input/reg_labourSupplyUtility.xlsx differ diff --git a/input/reg_leaveParentalHome.xlsx b/input/reg_leaveParentalHome.xlsx index bb8cc38f8..3aa7ef54a 100644 Binary files a/input/reg_leaveParentalHome.xlsx and b/input/reg_leaveParentalHome.xlsx differ diff --git a/input/reg_partnership.xlsx b/input/reg_partnership.xlsx index 9c689b853..c8e184dc0 100644 Binary files a/input/reg_partnership.xlsx and b/input/reg_partnership.xlsx differ diff --git a/input/reg_retirement.xlsx b/input/reg_retirement.xlsx index 08663ae2b..d18eca943 100644 Binary files a/input/reg_retirement.xlsx and b/input/reg_retirement.xlsx differ diff --git a/input/reg_wages.xlsx b/input/reg_wages.xlsx index 0fdacc128..56b3ca258 100644 Binary files a/input/reg_wages.xlsx and b/input/reg_wages.xlsx differ diff --git a/input/scenario_employments_furloughed.xlsx b/input/scenario_employments_furloughed.xlsx deleted file mode 100644 index 83c8100c5..000000000 Binary files a/input/scenario_employments_furloughed.xlsx and /dev/null differ diff --git a/input/scenario_macro_shocks.xlsx b/input/scenario_macro_shocks.xlsx new file mode 100644 index 000000000..5c10047f8 Binary files /dev/null and b/input/scenario_macro_shocks.xlsx differ diff --git a/input/scenario_parametricMatching.xlsx b/input/scenario_parametricMatching.xlsx index 70899584f..c4306bd35 100644 Binary files a/input/scenario_parametricMatching.xlsx and b/input/scenario_parametricMatching.xlsx differ diff --git a/input/scenario_retirementAgeFixed.xlsx b/input/scenario_retirementAgeFixed.xlsx index 11545850f..5c06484e7 100644 Binary files a/input/scenario_retirementAgeFixed.xlsx and b/input/scenario_retirementAgeFixed.xlsx differ diff --git a/input/system_bu_names.xlsx b/input/system_bu_names.xlsx index ca5b4337c..15998848c 100644 Binary files a/input/system_bu_names.xlsx and b/input/system_bu_names.xlsx differ diff --git a/input/time_series_factor.xlsx b/input/time_series_factor.xlsx index b3d76b728..b42e7e89b 100644 Binary files a/input/time_series_factor.xlsx and b/input/time_series_factor.xlsx differ diff --git a/pom.xml b/pom.xml index 03fd5dc21..3c05c45cd 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ com.github.jasmineRepo JAS-mine-core - 4.3.11 + 4.3.15 compile diff --git a/src/main/java/simpaths/data/ManagerRegressions.java b/src/main/java/simpaths/data/ManagerRegressions.java index b3c7754f7..6a62b5851 100644 --- a/src/main/java/simpaths/data/ManagerRegressions.java +++ b/src/main/java/simpaths/data/ManagerRegressions.java @@ -2,18 +2,18 @@ import microsim.statistics.IDoubleSource; -import microsim.statistics.regression.LinearRegression; -import microsim.statistics.regression.MultiLogitRegression; -import microsim.statistics.regression.OrderedProbitRegression; -import microsim.statistics.regression.ProbitRegression; +import microsim.statistics.regression.RegressionType; +import microsim.statistics.regression.*; import org.apache.commons.collections4.keyvalue.MultiKey; import org.apache.commons.collections4.map.MultiKeyMap; import simpaths.model.Person; -import simpaths.model.enums.IntegerValuedEnum; import simpaths.model.enums.Labour; import java.security.InvalidParameterException; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; /** @@ -23,12 +23,73 @@ */ public class ManagerRegressions { - public static ProbitRegression getProbitRegression(RegressionName regression) { + public static LinearRegression getLinearRegression(RegressionName regression) { + + if (!RegressionType.Linear.equals(regression.getType())) + throw new RuntimeException("requested LinearRegression object is not a linear regression"); + + switch (regression) { + case ChildcareC1b -> { + return Parameters.getRegChildcareC1b(); + } + case HealthHM1Level -> { + return Parameters.getRegHealthHM1Level(); + } + case HealthHM2LevelMales -> { + return Parameters.getRegHealthHM2LevelMales(); + } + case HealthHM2LevelFemales -> { + return Parameters.getRegHealthHM2LevelFemales(); + } + case SocialCareS1b -> { + return Parameters.getRegCareHoursS1b(); + } + case SocialCareS2g -> { + return Parameters.getRegPartnerCareHoursS2g(); + } + case SocialCareS2h -> { + return Parameters.getRegDaughterCareHoursS2h(); + } + case SocialCareS2i -> { + return Parameters.getRegSonCareHoursS2i(); + } + case SocialCareS2j -> { + return Parameters.getRegOtherCareHoursS2j(); + } + case SocialCareS2k -> { + return Parameters.getRegFormalCareHoursS2k(); + } + case SocialCareS3e -> { + return Parameters.getRegCareHoursProvS3e(); + } + case WagesMales -> { + return Parameters.getRegWagesMales(); + } + case WagesFemales -> { + return Parameters.getRegWagesFemales(); + } + case WagesMalesE -> { + return Parameters.getRegWagesMalesE(); + } + case WagesFemalesE -> { + return Parameters.getRegWagesFemalesE(); + } + case WagesMalesNE -> { + return Parameters.getRegWagesMalesNE(); + } + case WagesFemalesNE -> { + return Parameters.getRegWagesFemalesNE(); + } + default -> { + throw new RuntimeException("unrecognised regression (3)"); + } + } + } + + public static BinomialRegression getBinomialRegression(RegressionName regression) { - if (!RegressionType.StandardProbit.equals(regression.getType()) && - !RegressionType.AdjustedStandardProbit.equals(regression.getType()) && - !RegressionType.ReversedProbit.equals(regression.getType())) - throw new RuntimeException("requested ProbitRegression object is not a probit"); + if (!RegressionType.Probit.equals(regression.getType()) && !RegressionType.Logit.equals(regression.getType())) + throw new RuntimeException("requested Binomial regression is not recognised: " + regression.name()); switch (regression) { case EducationE1a -> { @@ -37,20 +98,35 @@ public static ProbitRegression getProbitRegression(RegressionName regression) { case EducationE1b -> { return Parameters.getRegEducationE1b(); } + case FertilityF1a -> { + return Parameters.getRegFertilityF1a(); + } + case FertilityF1b -> { + return Parameters.getRegFertilityF1b(); + } + case PartnershipU1a -> { + return Parameters.getRegPartnershipU1a(); + } + case PartnershipU1b -> { + return Parameters.getRegPartnershipU1b(); + } + case PartnershipU2b -> { + return Parameters.getRegPartnershipU2b(); + } case HealthH2b -> { return Parameters.getRegHealthH2b(); } - case UnemploymentU1a -> { - return Parameters.getRegUnemploymentMaleGraduateU1a(); + case HealthHM1Case -> { + return Parameters.getRegHealthHM1Case(); } - case UnemploymentU1b -> { - return Parameters.getRegUnemploymentMaleNonGraduateU1b(); + case HealthHM2CaseMales -> { + return Parameters.getRegHealthHM2CaseMales(); } - case UnemploymentU1c -> { - return Parameters.getRegUnemploymentFemaleGraduateU1c(); + case HealthHM2CaseFemales -> { + return Parameters.getRegHealthHM2CaseFemales(); } - case UnemploymentU1d -> { - return Parameters.getRegUnemploymentFemaleNonGraduateU1d(); + case SocialCareS1a -> { + return Parameters.getRegReceiveCareS1a(); } case SocialCareS2a -> { return Parameters.getRegNeedCareS2a(); @@ -58,34 +134,53 @@ public static ProbitRegression getProbitRegression(RegressionName regression) { case SocialCareS2b -> { return Parameters.getRegReceiveCareS2b(); } + case SocialCareS2d -> { + return Parameters.getRegReceiveCarePartnerS2d(); + } + case SocialCareS3a -> { + return Parameters.getRegCarePartnerProvCareToOtherS3a(); + } + case SocialCareS3b -> { + return Parameters.getRegNoCarePartnerProvCareToOtherS3b(); + } case SocialCareS3c -> { return Parameters.getRegNoPartnerProvCareToOtherS3c(); } - case PartnershipU1a -> { - return Parameters.getRegPartnershipU1a(); + case UnemploymentU1a -> { + return Parameters.getRegUnemploymentMaleGraduateU1a(); } - case PartnershipU1b -> { - return Parameters.getRegPartnershipU1b(); + case UnemploymentU1b -> { + return Parameters.getRegUnemploymentMaleNonGraduateU1b(); } - case PartnershipU2b -> { - return Parameters.getRegPartnershipU2b(); + case UnemploymentU1c -> { + return Parameters.getRegUnemploymentFemaleGraduateU1c(); } - case FertilityF1a -> { - return Parameters.getRegFertilityF1a(); + case UnemploymentU1d -> { + return Parameters.getRegUnemploymentFemaleNonGraduateU1d(); } - case FertilityF1b -> { - return Parameters.getRegFertilityF1b(); + default -> { + throw new RuntimeException("unrecognised regression (1)"); } + } + } + + public static OrderedRegression getOrderedRegression(RegressionName regression) { + + if (!RegressionType.OrderedLogit.equals(regression.getType()) && !RegressionType.OrderedProbit.equals(regression.getType())) + throw new RuntimeException("requested ordered regression is not recognised: " + regression.name()); + + switch (regression) { + default -> { throw new RuntimeException("unrecognised regression (1)"); } } } - public static OrderedProbitRegression getOrderedProbitRegression(RegressionName regression) { + public static GeneralisedOrderedRegression getGeneralisedOrderedRegression(RegressionName regression) { - if (!RegressionType.OrderedProbit.equals(regression.getType())) - throw new RuntimeException("requested OrderedProbitRegression object is not an ordered probit"); + if (!RegressionType.GenOrderedLogit.equals(regression.getType()) && !RegressionType.GenOrderedProbit.equals(regression.getType())) + throw new RuntimeException("requested generalised ordered regression is not recognised: " + regression.name()); switch (regression) { case HealthH1a -> { @@ -98,71 +193,62 @@ public static OrderedProbitRegression getOrderedProbitRegression(RegressionName return Parameters.getRegEducationE2a(); } default -> { - throw new RuntimeException("unrecognised regression (2)"); + throw new RuntimeException("unrecognised regression (1)"); } } } - public static MultiLogitRegression getMultiLogitRegression(RegressionName regression) { + public static MultinomialRegression getMultinomialRegression(RegressionName regression) { if (!RegressionType.MultinomialLogit.equals(regression.getType())) - throw new RuntimeException("requested MultiLogitRegression object is not a multinomial logit"); + throw new RuntimeException("requested multinomial regression is not recognised: " + regression.name()); switch (regression) { case SocialCareS2c -> { return Parameters.getRegSocialCareMarketS2c(); } + case SocialCareS2e -> { + return Parameters.getRegPartnerSupplementaryCareS2e(); + } + case SocialCareS2f -> { + return Parameters.getRegNotPartnerInformalCareS2f(); + } case SocialCareS3d -> { return Parameters.getRegInformalCareToS3d(); } default -> { - throw new RuntimeException("unrecognised regression (2)"); + throw new RuntimeException("unrecognised regression (1)"); } } } - public static LinearRegression getLinearRegression(RegressionName regression) { + public static IDiscreteChoiceModel getDiscreteVariableRegression(RegressionName regression) { - if (!RegressionType.Linear.equals(regression.getType())) - throw new RuntimeException("requested LinearRegression object is not a linear regression"); + switch (regression.getType()) { - switch (regression) { - case WagesMales -> { - return Parameters.getRegWagesMales(); - } - case WagesFemales -> { - return Parameters.getRegWagesFemales(); - } - case WagesMalesE -> { - return Parameters.getRegWagesMalesE(); - } - case WagesFemalesE -> { - return Parameters.getRegWagesFemalesE(); + case Logit, Probit -> { + return getBinomialRegression(regression); } - case WagesMalesNE -> { - return Parameters.getRegWagesMalesNE(); + case OrderedLogit, OrderedProbit -> { + return getOrderedRegression(regression); } - case WagesFemalesNE -> { - return Parameters.getRegWagesFemalesNE(); + case GenOrderedLogit, GenOrderedProbit -> { + return getGeneralisedOrderedRegression(regression); } - default -> { - throw new RuntimeException("unrecognised regression (3)"); + case MultinomialLogit -> { + return getMultinomialRegression(regression); } + default -> + throw new InvalidParameterException("Unrecognised call for discrete variable regression: " + regression.name()); } } public static double getScore(IDoubleSource person, RegressionName regression) { - if (RegressionType.Linear.equals(regression.getType())) { - + if (RegressionType.Linear.equals(regression.getType())) return getLinearRegression(regression).getScore(person, Person.DoublesVariables.class); - } else if (RegressionType.OrderedProbit.equals(regression.getType())) { - return getOrderedProbitRegression(regression).getScore(person, Person.DoublesVariables.class); - } else { - - return getProbitRegression(regression).getScore(person, Person.DoublesVariables.class); - } + throw new RuntimeException("unrecognised regression in getScore"); } public static double getRmse(RegressionName regression) { @@ -203,34 +289,6 @@ public static double getRmse(RegressionName regression) { return getRegressionCoeff(RegressionName.RMSE, code); } - public static double getProbability(IDoubleSource person, RegressionName regression) { - - double probability = getProbitRegression(regression).getProbability(person, Person.DoublesVariables.class); - if (probability > 1.0 || probability < 0.0) { - throw new InvalidParameterException("Problem evaluating probability from probit regression equation"); - } - return probability; - } - - public static double getProbability(double score, RegressionName regression) { - - double probability = getProbitRegression(regression).getProbability(score); - if (probability > 1.0 || probability < 0.0) { - throw new InvalidParameterException("Problem evaluating probability from probit regression equation"); - } - return probability; - } - - public static & IntegerValuedEnum> Map getMultinomialProbabilities(IDoubleSource obj, RegressionName regression) { - - if (RegressionType.OrderedProbit.equals(regression.getType())) { - return getOrderedProbitRegression(regression).getProbabilities(obj, Person.DoublesVariables.class); - } else if (RegressionType.MultinomialLogit.equals(regression.getType())) { - return getMultiLogitRegression(regression).getProbabilites(obj, Person.DoublesVariables.class); - } else - throw new InvalidParameterException("Probability requested for unrecognised multinomial regression equation"); - } - public static double getRegressionCoeff(Enum regression, String coeff) { Object oo = getRegressionCoeffObject(regression, coeff, false); if (oo instanceof Double) { @@ -244,27 +302,28 @@ public static double getRegressionCoeff(Enum regression, String coeff) { } } } + private static Object getRegressionCoeffObject(Enum regression, String coeff, boolean multi) { switch ((RegressionName) regression) { case WagesMalesE -> { return (multi) ? Parameters.getCoeffCovarianceWagesMalesE().getValue(coeff, "COEFFICIENT") : - Parameters.getCoeffCovarianceWagesMalesE().getValue(coeff); + Parameters.getCoeffCovarianceWagesMalesE().getValue(coeff); } case WagesMalesNE -> { return (multi) ? Parameters.getCoeffCovarianceWagesMalesNE().getValue(coeff, "COEFFICIENT") : - Parameters.getCoeffCovarianceWagesMalesNE().getValue(coeff); + Parameters.getCoeffCovarianceWagesMalesNE().getValue(coeff); } case WagesFemalesE -> { return (multi) ? Parameters.getCoeffCovarianceWagesFemalesE().getValue(coeff, "COEFFICIENT") : - Parameters.getCoeffCovarianceWagesFemalesE().getValue(coeff); + Parameters.getCoeffCovarianceWagesFemalesE().getValue(coeff); } case WagesFemalesNE -> { return (multi) ? Parameters.getCoeffCovarianceWagesFemalesNE().getValue(coeff, "COEFFICIENT") : - Parameters.getCoeffCovarianceWagesFemalesNE().getValue(coeff); + Parameters.getCoeffCovarianceWagesFemalesNE().getValue(coeff); } case RMSE -> { return (multi) ? Parameters.getCoefficientMapRMSE().getValue(coeff, "COEFFICIENT") : - Parameters.getCoefficientMapRMSE().getValue(coeff); + Parameters.getCoefficientMapRMSE().getValue(coeff); } default -> { throw new RuntimeException("Coefficient retrieval not supported for regression type " + regression.name()); @@ -272,35 +331,43 @@ private static Object getRegressionCoeffObject(Enum regression, String coeff, } } - public static E multiEvent(Map probs, double rand) { + public static double getProbability(IDoubleSource obj, RegressionName regression) { - double cprob = 0.0; - List keys = new ArrayList<>(); - for (E ee : probs.keySet()) { - if (probs.get(ee) != null) { - cprob += probs.get(ee); - for (int ii=0; ii ee.getValue()) { - keys.add(ii, ee); - break; - } - } - if (!keys.contains(ee)) - keys.add(ee); - } else { - throw new RuntimeException("problem identifying probabilities for multinomial object (2)"); - } - } + if (!RegressionType.Logit.equals(regression.getType()) && !RegressionType.Probit.equals(regression.getType())) + throw new InvalidParameterException("Failed to retrieve probability for unrecognised regression: " + regression.name()); + + return getBinomialRegression(regression).getProbability(obj, Person.DoublesVariables.class); + } + + public static & IntegerValuedEnum> double getProbability(E event, IDoubleSource obj, RegressionName regression) { + + return getDiscreteVariableRegression(regression).getProbability(event, obj, Person.DoublesVariables.class); + } + + public static & IntegerValuedEnum> Map getProbabilities(IDoubleSource obj, RegressionName regression) { + + return getDiscreteVariableRegression(regression).getProbabilities(obj, Person.DoublesVariables.class); + } + + public static & IntegerValuedEnum> E getEvent(Map probs, double rand) { + + List eventList = (List) probs.keySet(); + eventList.sort(Comparator.comparingInt(IntegerValuedEnum::getValue)); double prob = 0.0; - for (E ee : keys) { - prob += probs.get(ee) / cprob; + for (E event : eventList) { + prob += probs.get(event); if (rand < prob) { - return ee; + return event; } } - throw new RuntimeException("failed to identify new enumerator for multi-event (2)"); + throw new RuntimeException("failed to select event from discrete set"); + } + + public static & IntegerValuedEnum> E getEvent(IDoubleSource obj, RegressionName regression, double rand) { + + Map probs = getProbabilities(obj, regression); + return getEvent(probs, rand); } public static MultiKey multiEvent(MultiKeyMap probs, double rand) { @@ -335,6 +402,7 @@ public static MultiKey multiEvent(MultiKeyMap } throw new RuntimeException("failed to identify new enumerator for multi-event (3)"); } + private static int getMultiKeyValue(MultiKey ee) { int val = 0; int fctr = 1; diff --git a/src/main/java/simpaths/data/MultiValEvent.java b/src/main/java/simpaths/data/MultiValEvent.java index a5fd6a1b2..557f514da 100644 --- a/src/main/java/simpaths/data/MultiValEvent.java +++ b/src/main/java/simpaths/data/MultiValEvent.java @@ -1,8 +1,9 @@ package simpaths.data; -import simpaths.model.enums.IntegerValuedEnum; +import microsim.statistics.regression.IntegerValuedEnum; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -14,6 +15,7 @@ public class MultiValEvent { private E selectedEvent; private Map probs; private double randomDrawInitial, randomDrawAdjusted; + boolean problemWithProbs = false; // CONSTRUCTOR @@ -36,6 +38,9 @@ public double getRandomDrawAdjusted() { public void setRandomDrawAdjusted(double randomDrawAdjusted) { this.randomDrawAdjusted = randomDrawAdjusted; } + public boolean isProblemWithProbs() { + return problemWithProbs; + } // WORKER METHODS @@ -45,26 +50,16 @@ public E eval() { // evaluate cumulative probability and list keys in ascending order of associated probability double cprob = 0.0; - List keys = new ArrayList<>(); - for (E ee : probs.keySet()) { - - if (probs.get(ee) != null) { - - cprob += probs.get(ee); - for (int ii=0; ii ee.getValue()) { - - keys.add(ii, ee); - break; - } - } - if (!keys.contains(ee)) - keys.add(ee); - } else { + List keys = new ArrayList<>(probs.keySet()); + keys.sort(Comparator.comparingInt(IntegerValuedEnum::getValue)); + for (E ee : keys) { + if (probs.get(ee) == null) throw new RuntimeException("problem identifying probabilities for multinomial object (2)"); + if (probs.get(ee) < 0.0) { + probs.put(ee, 0.0); + problemWithProbs = true; } + cprob += probs.get(ee); } // identify selection and adjusted value of random draw diff --git a/src/main/java/simpaths/data/Parameters.java b/src/main/java/simpaths/data/Parameters.java index be784c2ed..8dcfc413e 100644 --- a/src/main/java/simpaths/data/Parameters.java +++ b/src/main/java/simpaths/data/Parameters.java @@ -2,15 +2,11 @@ package simpaths.data; // import Java packages -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.*; -// import plug-in packages -import simpaths.data.startingpop.DataParser; -import simpaths.model.AnnuityRates; -import simpaths.model.enums.*; +import microsim.data.MultiKeyCoefficientMap; +import microsim.data.excel.ExcelAssistant; +import microsim.statistics.regression.*; +import microsim.statistics.regression.RegressionType; import org.apache.commons.collections4.keyvalue.MultiKey; import org.apache.commons.collections4.map.LinkedMap; import org.apache.commons.collections4.map.MultiKeyMap; @@ -18,18 +14,21 @@ import org.apache.commons.math3.distribution.MultivariateNormalDistribution; import org.apache.commons.math3.distribution.NormalDistribution; import org.apache.commons.math3.util.Pair; - -// import JAS-mine packages -import microsim.data.excel.ExcelAssistant; -import microsim.data.MultiKeyCoefficientMap; -import microsim.statistics.regression.*; - -// import LABOURsim packages -import simpaths.model.taxes.DonorTaxUnit; +import simpaths.data.startingpop.DataParser; +import simpaths.model.AnnuityRates; import simpaths.model.decisions.Grids; +import simpaths.model.enums.*; +import simpaths.model.taxes.DonorTaxUnit; import simpaths.model.taxes.MatchFeature; import simpaths.model.taxes.database.TaxDonorDataParser; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.*; + +import static microsim.statistics.regression.RegressionUtils.appendCoefficientMaps; + /** * @@ -65,7 +64,7 @@ public class Parameters { "dwt", //household weight "les", //labour employment status + health status "lcs", //labour civil servant dummy indicator - "lcr01", //carer status for benefits (0 no 1 yes) + // "lcr01", //carer status for benefits (0 no 1 yes) "lhw", //hours worked per week "ddi", //disability status "yem", //employment income - used to construct work sector *NOT VALID FOR POLICY ANALYSIS* @@ -73,7 +72,7 @@ public class Parameters { }; public static final String[] DONOR_POLICY_VARIABLES = new String[] { - "xcc", //childcare costs + // "xcc", //childcare costs "ils_earns", //EUROMOD output variable:- total labour earnings (employment + self-employment income + potentially other labour earnings like temporary employment, depending on country classification) "ils_origy", //EUROMOD output variable:- all gross income from labour, private pensions, investment income, property income, private transfers etc. "ils_dispy", //Disposable income : from EUROMOD output data after tax / benefit transfers (monthly time-scale) @@ -91,9 +90,6 @@ public class Parameters { "drgn1", //region (NUTS1) "ydses_c5", //household income quantile "dhh_owned", //flag indicating if benefit unit owns a house - "liquid_wealth", //benefit unit net wealth non-pension non-housing wealth - "tot_pen", //benefit unit net pension wealth - "nvmhome", //benefit unit net housing wealth }; public static final String[] PERSON_VARIABLES_INITIAL = new String[] { @@ -110,9 +106,6 @@ public class Parameters { "ded", //in education dummy "der", //return to education dummy "dhe", //health status - "dhm", //mental health status - "scghq2_dv", //mental health status case based - "dhm_ghq", //mental health status case based dummy (1 = psychologically distressed) "dcpyy", //years in partnership "dcpagdf", //partners age difference "dnc02", //number children aged 0-2 @@ -129,20 +122,13 @@ public class Parameters { "swv", //system variable - wave "dgn", //gender "les_c4", //labour employment status + "l1_les_c4", //lag(1) of labour employment status "lhw", //hours worked per week "adultchildflag", //flag indicating adult child living at home in the data "dhh_owned", //flag indicating if individual is a homeowner - "potential_earnings_hourly", //initial value of hourly earnings from the data - "l1_potential_earnings_hourly", //lag(1) of initial value of hourly earnings from the data - "need_socare", //indicator that the individual needs social care - "formal_socare_hrs", //number of hours of formal care received - "formal_socare_cost", //cost of formal care received - "partner_socare_hrs", //number of hours of informal care received from partner - "daughter_socare_hrs", //number of hours of informal care received from daughter - "son_socare_hrs", //number of hours of informal care received from son - "other_socare_hrs", //number of hours of informal care received from other - "aidhrs", //number of hours of informal care provided (total) - "careWho" //indicator for whom informal care is provided + "obs_earnings_hourly", //initial value of hourly earnings from the data + "l1_obs_earnings_hourly", //lag(1) of initial value of hourly earnings from the data + "liwwh", // number of years in employment //"yem", //employment income //"yse", //self-employment income @@ -152,7 +138,7 @@ public class Parameters { }; //Parameters for managing tax and benefit imputations - public static final int TAXDB_REGIMES = 5; + public static final int TAXDB_REGIMES = 6; private static Map> taxdbCounter = new HashMap>(); // records, for each of the three donor keys (first Integer), the increments (second Integer) associated with one unit change in characteristic (String). The properties of taxdbCounter are specific to the KeyFunction used (and are populated by the associated function) private static List donorPool; // list of donors for tax imputation, in ascending order by private (original) income private static Map,List> taxdbReferences = new HashMap<>(); // for Triple returns a list of indices to donorPool that describes members of grouping, in ascending order by private income @@ -206,6 +192,7 @@ else if(numberOfChildren <= 5) { return 3.; } } + public static final double AgeDiscrepancyConstraint = 10; //Difference of age must equal of be below this value (so we allow 10 year cumulated age difference) public static final TreeSet EarningsDiscrepancyConstraint = new TreeSet<>(Arrays.asList(0.01, 0.02, 0.03, 0.04, 0.05)); //Proportional difference @@ -223,13 +210,13 @@ else if(numberOfChildren <= 5) { public static final int HOURS_IN_WEEK = 24 * 7; //This is used to calculate leisure in labour supply //Is it possible for people to start going to the labour module (e.g. age 17) while they are living with parents (until age 18)? //Cannot see how its possible if it is the household that decides how much labour to supply. If someone finishes school at 17, they need to leave home before they can enter the labour market. So set age for finishing school and leaving home to 18. - public static final int MAX_LABOUR_HOURS_IN_WEEK = 48; + public static final int MAX_LABOUR_HOURS_IN_WEEK = 45; public static final boolean USE_CONTINUOUS_LABOUR_SUPPLY_HOURS = true; // If true, a random number of hours of weekly labour supply within each bracket will be generated. Otherwise, each discrete choice of labour supply corresponds to a fixed number of hours of labour supply, which is the same for all persons public static int maxAge; // maximum age possible in simulation public static final int AGE_TO_BECOME_RESPONSIBLE = 18; // Age become reference person of own benefit unit public static final int MIN_AGE_TO_LEAVE_EDUCATION = 16; // Minimum age for a person to leave (full-time) education public static final int MAX_AGE_TO_LEAVE_CONTINUOUS_EDUCATION = 29; - public static final int MAX_AGE_TO_ENTER_EDUCATION = 45; + public static final int MAX_AGE_TO_ENTER_EDUCATION = 35; public static final int MIN_AGE_COHABITATION = AGE_TO_BECOME_RESPONSIBLE; // Min age a person can marry public static final int MIN_AGE_TO_HAVE_INCOME = 16; //Minimum age to have non-employment non-benefit income public static final int MIN_AGE_TO_RETIRE = 50; //Minimum age to consider retirement @@ -241,7 +228,7 @@ else if(numberOfChildren <= 5) { public static final double ANNUITY_RATE_OF_RETURN = 0.015; public static AnnuityRates annuityRates; public static final int MIN_HOURS_FULL_TIME_EMPLOYED = 25; // used to distinguish full-time from part-time employment (needs to be consistent with Labour enum) - public static final double MIN_HOURLY_WAGE_RATE = 1.5; + public static final double MIN_HOURLY_WAGE_RATE = 0.0; public static final double MAX_HOURLY_WAGE_RATE = 150.0; public static final double MAX_HOURS_WEEKLY_FORMAL_CARE = 150.0; public static final double MAX_HOURS_WEEKLY_INFORMAL_CARE = 16 * 7; @@ -257,7 +244,7 @@ else if(numberOfChildren <= 5) { //public static int MAX_AGE_IN_EDUCATION;// = MAX_AGE;//30; // Max age a person can stay in education //Cannot set here, as MAX_AGE is not known yet. Now set to MAX_AGE in buildObjects in Model class. //public static int MAX_AGE_MARRIAGE;// = MAX_AGE;//75; // Max age a person can marry //Cannot set here, as MAX_AGE is not known yet. Now set to MAX_AGE in buildObjects in Model class. private static final int MIN_START_YEAR = 2011; //Minimum allowed starting point. Should correspond to the oldest initial population. - private static final int MAX_START_YEAR = 2021; //Maximum allowed starting point. Should correspond to the most recent initial population. + private static final int MAX_START_YEAR = 2020; //Maximum allowed starting point. Should correspond to the most recent initial population. public static int startYear; public static int endYear; private static final int MIN_START_YEAR_TRAINING = 2019; @@ -274,7 +261,7 @@ else if(numberOfChildren <= 5) { public static final boolean systemOut = true; //Bootstrap all the regression coefficients if true, or only the female labour participation regressions when false - public static final boolean bootstrapAll = false; + public static final boolean bootstrapAll = true; //Scheduling public static final int MODEL_ORDERING = 0; @@ -331,6 +318,7 @@ else if(numberOfChildren <= 5) { public static Map> EUROMODpolicyScheduleSystemYearMap = new TreeMap<>(); // This map stores year from which policy applies, and then a Pair of . This is used when uprating values from the policy system year to a current simulated year. private static MultiKeyMap fertilityRateByRegionYear; private static Map fertilityRateByYear; + private static Map retiredShareByYear; private static MultiKeyCoefficientMap populationProjections; public static final int ALIGN_MIN_AGE_ASSUME_DEATH = 65; public static final int ALIGN_MAX_AGE_REQUIRE_MATCH = 65; @@ -346,10 +334,10 @@ else if(numberOfChildren <= 5) { private static boolean flagDefaultToTimeSeriesAverages; private static Double averageSavingReturns, averageDebtCostLow, averageDebtCostHigh; private static MultiKeyCoefficientMap upratingIndexMapRealGDP, upratingIndexMapInflation, socialCareProvisionTimeAdjustment, - partnershipTimeAdjustment, fertilityTimeAdjustment, utilityTimeAdjustmentSingleMales, utilityTimeAdjustmentSingleFemales, + partnershipTimeAdjustment, retirementTimeAdjustment, fertilityTimeAdjustment, disabilityTimeAdjustment, studentsTimeAdjustment, utilityTimeAdjustment, utilityTimeAdjustmentSingleMales, utilityTimeAdjustmentSingleFemales, utilityTimeAdjustmentCouples, upratingIndexMapRealWageGrowth, priceMapRealSavingReturns, priceMapRealDebtCostLow, priceMapRealDebtCostHigh, - wageRateFormalSocialCare, socialCarePolicy, partneredShare, employedShareSingleMales, employedShareSingleFemales, employedShareCouples; - public static Map partnershipAlignAdjustment, fertilityAlignAdjustment; + wageRateFormalSocialCare, socialCarePolicy, partneredShare, retiredShare, disabledShare, studentShare, employedShare, employedShareSingleMales, employedShareSingleFemales, employedShareCouples; + public static Map partnershipAlignAdjustment, fertilityAlignAdjustment, retirementAlignAdjustment, studentsAlignAdjustment, disabilityAlignAdjustment; public static MultiKeyMap upratingFactorsMap = new MultiKeyMap<>(); //Education level projections @@ -362,10 +350,6 @@ else if(numberOfChildren <= 5) { //Employment alignment targets private static MultiKeyCoefficientMap employmentAlignment; - //For marriage types: - private static MultiKeyCoefficientMap marriageTypesFrequency; - private static Map> marriageTypesFrequencyByGenderAndRegion; - //Mean and covariances for parametric matching private static MultiKeyCoefficientMap meanCovarianceParametricMatching; @@ -404,8 +388,6 @@ else if(numberOfChildren <= 5) { private static int unemploymentRatesFemaleNonGraduatesMinYear; private static int unemploymentRatesFemaleNonGraduatesMaxAge; - //Number of employments on full and flexible furlough from HMRC statistics, used as regressors in the Covid-19 module - private static MultiKeyCoefficientMap employmentsFurloughedFull; private static MultiKeyCoefficientMap employmentsFurloughedFlex; /////////////////////////////////////////////////////////////////// REGRESSION COEFFICIENTS ////////////////////////////////////////// @@ -478,8 +460,8 @@ else if(numberOfChildren <= 5) { //Income private static MultiKeyCoefficientMap coeffCovarianceIncomeI1a; //Linear regression non-employment non-benefit income if in continuous education private static MultiKeyCoefficientMap coeffCovarianceIncomeI1b; //Linear regression non-employment non-benefit income if not in continuous education - private static MultiKeyCoefficientMap coeffCovarianceIncomeI3a; //Capital income if in continuous education - private static MultiKeyCoefficientMap coeffCovarianceIncomeI3b; //Capital income if not in continuous education + private static MultiKeyCoefficientMap coeffCovarianceIncomeI3a_amount; //Capital income if in continuous education + private static MultiKeyCoefficientMap coeffCovarianceIncomeI3b_amount; //Capital income if not in continuous education private static MultiKeyCoefficientMap coeffCovarianceIncomeI3c; //Pension income for those aged over 50 who are not in continuous education private static MultiKeyCoefficientMap coeffCovarianceIncomeI4a, coeffCovarianceIncomeI4b; // Pension income for those moving from employment to retirement (I4a) and those already retired (I4b) private static MultiKeyCoefficientMap coeffCovarianceIncomeI5a_selection, coeffCovarianceIncomeI5b_amount; // Selection equation for receiving pension income for those moving from employment to retirement (I5a) and amount in levels (I5b) @@ -502,12 +484,10 @@ else if(numberOfChildren <= 5) { private static MultiKeyCoefficientMap coeffLabourSupplyUtilityMalesWithDependent; //For use with couples where only male is flexible in labour supply (so has a dependent) private static MultiKeyCoefficientMap coeffLabourSupplyUtilityFemalesWithDependent; private static MultiKeyCoefficientMap coeffLabourSupplyUtilityACMales; //Adult children, male + private static MultiKeyCoefficientMap coeffLabourSupplyUtilityACFemales; //Adult children, female private static MultiKeyCoefficientMap coeffLabourSupplyUtilityCouples; - // coefficients for Covid-19 labour supply models below - // Initialisation - private static MultiKeyCoefficientMap coeffCovarianceC19LS_SE; // Transitions // From lagged state "employed" private static MultiKeyCoefficientMap coeffC19LS_E1_NE; // For multi probit regressions, have to specify coefficients for each possible outcome, with "no changes" being the baseline. NE is not-employed. @@ -629,62 +609,62 @@ else if(numberOfChildren <= 5) { /////////////////////////////////////////////////////////////////// REGRESSION OBJECTS ////////////////////////////////////////// //Health - private static OrderedProbitRegression regHealthH1a; - private static OrderedProbitRegression regHealthH1b; - private static ProbitRegression regHealthH2b; + private static GeneralisedOrderedRegression regHealthH1a; + private static GeneralisedOrderedRegression regHealthH1b; + private static BinomialRegression regHealthH2b; //Social care - private static ProbitRegression regReceiveCareS1a; + private static BinomialRegression regReceiveCareS1a; private static LinearRegression regCareHoursS1b; - private static ProbitRegression regNeedCareS2a; - private static ProbitRegression regReceiveCareS2b; - private static MultiLogitRegression regSocialCareMarketS2c; - private static ProbitRegression regReceiveCarePartnerS2d; - private static MultiLogitRegression regPartnerSupplementaryCareS2e; - private static MultiLogitRegression regNotPartnerInformalCareS2f; + private static BinomialRegression regNeedCareS2a; + private static BinomialRegression regReceiveCareS2b; + private static MultinomialRegression regSocialCareMarketS2c; + private static BinomialRegression regReceiveCarePartnerS2d; + private static MultinomialRegression regPartnerSupplementaryCareS2e; + private static MultinomialRegression regNotPartnerInformalCareS2f; private static LinearRegression regPartnerCareHoursS2g; private static LinearRegression regDaughterCareHoursS2h; private static LinearRegression regSonCareHoursS2i; private static LinearRegression regOtherCareHoursS2j; private static LinearRegression regFormalCareHoursS2k; - private static ProbitRegression regCarePartnerProvCareToOtherS3a; - private static ProbitRegression regNoCarePartnerProvCareToOtherS3b; - private static ProbitRegression regNoPartnerProvCareToOtherS3c; - private static MultiLogitRegression regInformalCareToS3d; + private static BinomialRegression regCarePartnerProvCareToOtherS3a; + private static BinomialRegression regNoCarePartnerProvCareToOtherS3b; + private static BinomialRegression regNoPartnerProvCareToOtherS3c; + private static MultinomialRegression regInformalCareToS3d; private static LinearRegression regCareHoursProvS3e; //Unemployment - private static ProbitRegression regUnemploymentMaleGraduateU1a; - private static ProbitRegression regUnemploymentMaleNonGraduateU1b; - private static ProbitRegression regUnemploymentFemaleGraduateU1c; - private static ProbitRegression regUnemploymentFemaleNonGraduateU1d; + private static BinomialRegression regUnemploymentMaleGraduateU1a; + private static BinomialRegression regUnemploymentMaleNonGraduateU1b; + private static BinomialRegression regUnemploymentFemaleGraduateU1c; + private static BinomialRegression regUnemploymentFemaleNonGraduateU1d; //Health mental private static LinearRegression regHealthHM1Level; private static LinearRegression regHealthHM2LevelMales; private static LinearRegression regHealthHM2LevelFemales; - private static LogitRegression regHealthHM1Case; - private static LogitRegression regHealthHM2CaseMales; - private static LogitRegression regHealthHM2CaseFemales; + private static BinomialRegression regHealthHM1Case; + private static BinomialRegression regHealthHM2CaseMales; + private static BinomialRegression regHealthHM2CaseFemales; //Education - private static ProbitRegression regEducationE1a; - private static ProbitRegression regEducationE1b; - private static OrderedProbitRegression regEducationE2a; + private static BinomialRegression regEducationE1a; + private static BinomialRegression regEducationE1b; + private static GeneralisedOrderedRegression regEducationE2a; //Partnership - private static ProbitRegression regPartnershipU1a; - private static ProbitRegression regPartnershipU1b; - private static ProbitRegression regPartnershipU2b; + private static BinomialRegression regPartnershipU1a; + private static BinomialRegression regPartnershipU1b; + private static BinomialRegression regPartnershipU2b; - private static ProbitRegression regPartnershipITU1; - private static ProbitRegression regPartnershipITU2; + private static BinomialRegression regPartnershipITU1; + private static BinomialRegression regPartnershipITU2; //Fertility - private static ProbitRegression regFertilityF1a; - private static ProbitRegression regFertilityF1b; - private static ProbitRegression regFertilityF1; + private static BinomialRegression regFertilityF1a; + private static BinomialRegression regFertilityF1b; + private static BinomialRegression regFertilityF1; //Income private static LinearRegression regIncomeI1a; @@ -696,20 +676,20 @@ else if(numberOfChildren <= 5) { private static LinearRegression regIncomeI4b; private static LinearRegression regIncomeI5b_amount; private static LinearRegression regIncomeI6b_amount; - private static LogitRegression regIncomeI3a_selection; - private static LogitRegression regIncomeI3b_selection; - private static LogitRegression regIncomeI5a_selection; - private static LogitRegression regIncomeI6a_selection; + private static BinomialRegression regIncomeI3a_selection; + private static BinomialRegression regIncomeI3b_selection; + private static BinomialRegression regIncomeI5a_selection; + private static BinomialRegression regIncomeI6a_selection; //Homeownership - private static ProbitRegression regHomeownershipHO1a; + private static BinomialRegression regHomeownershipHO1a; //New regressions from Lia - private static LogitRegression regSchooling; - private static MultiLogitRegression regEducationLevel; + private static BinomialRegression regSchooling; + private static MultinomialRegression regEducationLevel; //New simple educ level - private static MultiLogitRegression regSimpleEducLevel; + private static MultinomialRegression regSimpleEducLevel; //For Labour market private static LinearRegression regWagesMales; @@ -733,13 +713,13 @@ else if(numberOfChildren <= 5) { // Covid-19 labour transitions regressions below // Initialisation - private static ProbitRegression regC19LS_SE; // Assigns self-employed status in the simulated population + private static BinomialRegression regC19LS_SE; // Assigns self-employed status in the simulated population // Transitions - private static MultiLogitRegression regC19LS_E1; // Models transitions from employment - private static MultiLogitRegression regC19LS_FF1; // Models transitions from furlough full - private static MultiLogitRegression regC19LS_FX1; // Models transitions from furlough flex - private static MultiLogitRegression regC19LS_S1; // Models transitions from self-employment - private static MultiLogitRegression regC19LS_U1; // Models transitions from non-employment + private static MultinomialRegression regC19LS_E1; // Models transitions from employment + private static MultinomialRegression regC19LS_FF1; // Models transitions from furlough full + private static MultinomialRegression regC19LS_FX1; // Models transitions from furlough flex + private static MultinomialRegression regC19LS_S1; // Models transitions from self-employment + private static MultinomialRegression regC19LS_U1; // Models transitions from non-employment // Hours of work private static LinearRegression regC19LS_E2a; private static LinearRegression regC19LS_E2b; @@ -750,21 +730,21 @@ else if(numberOfChildren <= 5) { private static LinearRegression regC19LS_U2a; // Probability of SEISS - private static LogitRegression regC19LS_S3; + private static BinomialRegression regC19LS_S3; //Leaving parental home - private static ProbitRegression regLeaveHomeP1a; + private static BinomialRegression regLeaveHomeP1a; //Retirement - private static ProbitRegression regRetirementR1a; - private static ProbitRegression regRetirementR1b; + private static BinomialRegression regRetirementR1a; + private static BinomialRegression regRetirementR1b; //Childcare - private static ProbitRegression regChildcareC1a; + private static BinomialRegression regChildcareC1a; private static LinearRegression regChildcareC1b; - private static ProbitRegression regBirthFemales; - private static ProbitRegression regUnionFemales; + private static BinomialRegression regBirthFemales; + private static BinomialRegression regUnionFemales; private static Set countryRegions; private static Map unemploymentRatesByRegion; public static boolean isFixTimeTrend; @@ -780,17 +760,18 @@ else if(numberOfChildren <= 5) { /** - * * METHOD TO LOAD PARAMETERS FOR GIVEN COUNTRY - * @param country * + * @param country + * @param macroShockPopulation */ public static void loadParameters(Country country, int maxAgeModel, boolean enableIntertemporalOptimisations, boolean projectFormalChildcare, boolean projectSocialCare, boolean donorPoolAveraging1, boolean fixTimeTrend, boolean defaultToTimeSeriesAverages, boolean taxDBMatches, Integer timeTrendStops, int startYearModel, int endYearModel, double interestRateInnov1, double disposableIncomeFromLabourInnov1, boolean flagSuppressChildcareCosts1, - boolean flagSuppressSocialCareCosts1) { + boolean flagSuppressSocialCareCosts1, MacroScenarioPopulation macroShockPopulation, + MacroScenarioProductivity macroShockProductivity, MacroScenarioGreenPolicy macroShockGreenPolicy, boolean macroShocksOn) { // display a dialog box to let the user know what is happening System.out.println("Loading model parameters"); @@ -801,7 +782,7 @@ public static void loadParameters(Country country, int maxAgeModel, boolean enab endYear = endYearModel; EUROMODpolicySchedule = calculateEUROMODpolicySchedule(country); - taxDonorInputFileName = "population_" + country; + //taxDonorInputFileName = "population_" + country; populationInitialisationInputFileName = "population_initial_" + country; setCountryRegions(country); setEnableIntertemporalOptimisations(enableIntertemporalOptimisations); @@ -811,11 +792,7 @@ public static void loadParameters(Country country, int maxAgeModel, boolean enab instantiateAlignmentMaps(); // scenario parameters - if (country.equals(Country.IT)) { - SAVINGS_RATE = 0.056; - } else { - SAVINGS_RATE = 0.056; - } + SAVINGS_RATE = 0.056; saveImperfectTaxDBMatches = taxDBMatches; flagDefaultToTimeSeriesAverages = defaultToTimeSeriesAverages; @@ -831,7 +808,7 @@ public static void loadParameters(Country country, int maxAgeModel, boolean enab // unemploymentRatesByRegion = new LinkedHashMap<>(); // unemploymentRates = ExcelAssistant.loadCoefficientMap("input/scenario_unemploymentRates.xlsx", countryString, 1, 46); - fixedRetireAge = ExcelAssistant.loadCoefficientMap("input/scenario_retirementAgeFixed.xlsx", countryString, 1, 2); + fixedRetireAge = ExcelAssistant.loadCoefficientMap("input/scenario_retirementAgeFixed.xlsx", countryString, 1, 2); //# /* rawProbSick = ExcelAssistant.loadCoefficientMap("input/scenario_probSick.xls", country.toString(), 2, 1); for (Object o: rawProbSick.keySet()) { @@ -856,313 +833,224 @@ public static void loadParameters(Country country, int maxAgeModel, boolean enab probSick = new MultiKeyMap(); */ - // alignment parameters - populationProjections = ExcelAssistant.loadCoefficientMap("input/align_popProjections.xlsx", countryString, 3, 110); + /* + Code below introduces macro shocks in terms of population, productivity, and employment + + */ + // Macro population switch + if (macroShocksOn) { + switch (macroShockPopulation) { + case High: + populationProjections = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", "population_high", 3, 50); + + // Productivity sub-switch + switch (macroShockProductivity) { + case Baseline: + // Green policy sub-switch + switch (macroShockGreenPolicy) { + case Yes: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_highpop_baseprod_green", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_highpop_baseprod_green", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_highpop_baseprod_green", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_highpop_baseprod_green", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_highpop_baseprod_green", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_highpop_baseprod_green", 1, 1); + break; + case No: + default: + throw new IllegalArgumentException("Unsupported combination: High population + " + + macroShockProductivity + " + " + macroShockGreenPolicy); + } + break; + case High: + case Low: + throw new IllegalArgumentException("Unsupported combination: High population + " + + macroShockProductivity); + default: + throw new IllegalStateException("Unexpected productivity value: " + macroShockProductivity); + } + break; + + case Low: + populationProjections = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", "population_low", 3, 50); + + switch (macroShockProductivity) { + case Baseline: + switch (macroShockGreenPolicy) { + case Yes: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_lowpop_baseprod_green", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_lowpop_baseprod_green", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_lowpop_baseprod_green", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_lowpop_baseprod_green", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_lowpop_baseprod_green", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_lowpop_baseprod_green", 1, 1); + break; + case No: + default: + throw new IllegalArgumentException("Unsupported combination: Low population + " + + macroShockProductivity + " + " + macroShockGreenPolicy); + } + break; + case High: + case Low: + throw new IllegalArgumentException("Unsupported combination: Low population + " + + macroShockProductivity); + default: + throw new IllegalStateException("Unexpected productivity value: " + macroShockProductivity); + } + break; + + case Baseline: + default: + populationProjections = ExcelAssistant.loadCoefficientMap("input/align_popProjections.xlsx", countryString, 3, 50); + + switch (macroShockProductivity) { + case Baseline: + switch (macroShockGreenPolicy) { + case Yes: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_basepop_baseprod_green", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_basepop_baseprod_green", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + break; + case No: + default: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_basepop_baseprod", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_basepop_baseprod", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + break; + } + break; + case High: + switch (macroShockGreenPolicy) { + case Yes: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_basepop_highprod_green", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_basepop_highprod_green", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod_green", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod_green", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod_green", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + break; + case No: + default: + upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_gdp_basepop_highprod", 1, 1); + upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_wage_basepop_highprod", 1, 1); + rebaseIndexMap(TimeSeriesVariable.GDP); + rebaseIndexMap(TimeSeriesVariable.WageGrowth); + employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod", 1, 1); + employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod", 1, 1); + employedShareCouples = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_highprod", 1, 1); + employedShare = ExcelAssistant.loadCoefficientMap("input/scenario_macro_shocks.xlsx", country.toString() + "_emp_basepop_baseprod_green", 1, 1); + break; + } + break; + case Low: + throw new IllegalArgumentException("Unsupported combination: Baseline population + Low productivity"); + default: + throw new IllegalStateException("Unexpected productivity value: " + macroShockProductivity); + } + break; + } + } else { + populationProjections = ExcelAssistant.loadCoefficientMap("input/align_popProjections.xlsx", countryString, 3, 50); + } + + setMapBounds(MapBounds.Population, countryString); //Alignment of education levels + // Not currently used. Consider removing. projectionsHighEdu = ExcelAssistant.loadCoefficientMap("input/align_educLevel.xlsx", countryString + "_High", 1, 2); projectionsLowEdu = ExcelAssistant.loadCoefficientMap("input/align_educLevel.xlsx", countryString + "_Low", 1, 2); studentShareProjections = ExcelAssistant.loadCoefficientMap("input/align_student_under30.xlsx", countryString, 1, 40); //Employment alignment - employmentAlignment = ExcelAssistant.loadCoefficientMap("input/align_employment.xlsx", countryString, 2, 40); + // employmentAlignment = ExcelAssistant.loadCoefficientMap("input/align_employment.xlsx", countryString, 2, 40); + + //Fertility rates: + fertilityProjectionsByYear = ExcelAssistant.loadCoefficientMap("input/projections_fertility.xlsx", countryString + "_FertilityByYear", 1, 90); + setMapBounds(MapBounds.Fertility, countryString); - //Marriage types frequencies: - marriageTypesFrequency = ExcelAssistant.loadCoefficientMap("input/marriageTypes2.xlsx", countryString, 2, 1); - marriageTypesFrequencyByGenderAndRegion = new LinkedHashMap>(); //Create a map of maps to store the frequencies + //RMSE + coefficientMapRMSE = ExcelAssistant.loadCoefficientMap("input/reg_RMSE.xlsx", countryString, 1, 1); //Mortality rates - mortalityProbabilityByGenderAgeYear = ExcelAssistant.loadCoefficientMap("input/projections_mortality.xlsx", countryString + "_MortalityByGenderAgeYear", 2, 120); + mortalityProbabilityByGenderAgeYear = ExcelAssistant.loadCoefficientMap("input/projections_mortality.xlsx", countryString + "_MortalityByGenderAgeYear", 2, 111); setMapBounds(MapBounds.Mortality, countryString); - //Fertility rates: - fertilityProjectionsByYear = ExcelAssistant.loadCoefficientMap("input/projections_fertility.xlsx", countryString + "_FertilityByYear", 1, 71); - setMapBounds(MapBounds.Fertility, countryString); //Unemployment rates - unemploymentRatesMaleGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesMaleGraduates", 1, 49); - setMapBounds(MapBounds.UnemploymentMaleGraduates, countryString); - unemploymentRatesMaleNonGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesMaleNonGraduates", 1, 49); - setMapBounds(MapBounds.UnemploymentMaleNonGraduates, countryString); - unemploymentRatesFemaleGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesFemaleGraduates", 1, 49); - setMapBounds(MapBounds.UnemploymentFemaleGraduates, countryString); - unemploymentRatesFemaleNonGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesFemaleNonGraduates", 1, 49); - setMapBounds(MapBounds.UnemploymentFemaleNonGraduates, countryString); - - //RMSE - coefficientMapRMSE = ExcelAssistant.loadCoefficientMap("input/reg_RMSE.xlsx", countryString, 1, 1); + // unemploymentRatesMaleGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesMaleGraduates", 1, 49); + // setMapBounds(MapBounds.UnemploymentMaleGraduates, countryString); + // unemploymentRatesMaleNonGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesMaleNonGraduates", 1, 49); + // setMapBounds(MapBounds.UnemploymentMaleNonGraduates, countryString); + // unemploymentRatesFemaleGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesFemaleGraduates", 1, 49); + // setMapBounds(MapBounds.UnemploymentFemaleGraduates, countryString); + // unemploymentRatesFemaleNonGraduatesByAgeYear = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_RatesFemaleNonGraduates", 1, 49); + // setMapBounds(MapBounds.UnemploymentFemaleNonGraduates, countryString); - //Employments on furlough - employmentsFurloughedFull = ExcelAssistant.loadCoefficientMap("input/scenario_employments_furloughed.xlsx", countryString + "_FullFurlough", 2, 1); - employmentsFurloughedFlex = ExcelAssistant.loadCoefficientMap("input/scenario_employments_furloughed.xlsx", countryString + "_FlexibleFurlough", 2, 1); //Load country specific data - int columnsWagesMales = -1; - int columnsWagesMalesNE = -1; - int columnsWagesMalesE = -1; - int columnsWagesFemales = -1; - int columnsWagesFemalesNE = -1; - int columnsWagesFemalesE = -1; - int columnsEmploymentSelectionMales = -1; - int columnsEmploymentSelectionMalesNE = -1; - int columnsEmploymentSelectionMalesE = -1; - int columnsEmploymentSelectionFemales = -1; - int columnsEmploymentSelectionFemalesNE = -1; - int columnsEmploymentSelectionFemalesE = -1; - int columnsLabourSupplyUtilityMales = -1; - int columnsLabourSupplyUtilityFemales = -1; - int columnsLabourSupplyUtilityMalesWithDependent = -1; - int columnsLabourSupplyUtilityFemalesWithDependent = -1; - int columnsLabourSupplyUtilityACMales = -1; - int columnsLabourSupplyUtilityACFemales = -1; - int columnsLabourSupplyUtilityCouples = -1; - int columnsLabourCovid19_SE = -1; - int columnsLabourCovid19_2a_processes = -1; - int columnsHealthH1a = -1; - int columnsHealthH1b = -1; - int columnsHealthH2b = -1; - int columnsHealthHM1 = -1; - int columnsHealthHM2Males = -1; - int columnsHealthHM2Females = -1; - int columnsSocialCareS1a = -1; - int columnsSocialCareS1b = -1; - int columnsSocialCareS2a = -1; - int columnsSocialCareS2b = -1; - int columnsSocialCareS2c = -1; - int columnsSocialCareS2d = -1; - int columnsSocialCareS2e = -1; - int columnsSocialCareS2f = -1; - int columnsSocialCareS2g = -1; - int columnsSocialCareS2h = -1; - int columnsSocialCareS2i = -1; - int columnsSocialCareS2j = -1; - int columnsSocialCareS2k = -1; - int columnsSocialCareS3a = -1; - int columnsSocialCareS3b = -1; - int columnsSocialCareS3c = -1; - int columnsSocialCareS3d = -1; - int columnsSocialCareS3e = -1; - int columnsUnemploymentU1a = -1; - int columnsUnemploymentU1b = -1; - int columnsUnemploymentU1c = -1; - int columnsUnemploymentU1d = -1; - int columnsEducationE1a = -1; - int columnsEducationE1b = -1; - int columnsEducationE2a = -1; - int columnsPartnershipU1a = -1; - int columnsPartnershipU1b = -1; - int columnsPartnershipU2b = -1; - int columnsPartnershipU1 = -1; - int columnsPartnershipU2 = -1; - int columnsFertilityF1a = -1; - int columnsFertilityF1b = -1; - int columnsFertilityF1 = -1; - int columnsIncomeI1a = -1; - int columnsIncomeI1b = -1; - int columnsIncomeI3a = -1; - int columnsIncomeI3b = -1; - int columnsIncomeI3c = -1; - int columnsIncomeI4a = -1; - int columnsIncomeI4b = -1; - int columnsIncomeI5a = -1; - int columnsIncomeI5b = -1; - int columnsIncomeI6a = -1; - int columnsIncomeI6b = -1; - int columnsIncomeI3a_selection = -1; - int columnsIncomeI3b_selection = -1; - int columnsLeaveHomeP1a = -1; - int columnsHomeownership = -1; - int columnsRetirementR1a = -1; - int columnsRetirementR1b = -1; - int columnsChildcareC1a = -1; - int columnsChildcareC1b = -1; - //For validation below: - int columnsValidationStudentsByAge = -1; - int columnsValidationStudentsByRegion = -1; - int columnsValidationEducationLevel = -1; - int columnsValidationEducationLevelByAge = -1; - int columnsValidationEducationLevelByRegion = -1; - int columnsValidationPartneredBUShareByRegion = -1; - int columnsValidationDisabledByGender = -1; - int columnsValidationDisabledByAgeGroup = -1; - int columnsValidationHealthByAgeGroup = -1; - int columnsValidationMentalHealthByAgeGroup = -1; - int columnsValidationEmploymentByGender = -1; - int columnsValidationEmploymentByGenderAndAge = -1; - int columnsValidationEmploymentByMaternity = -1; - int columnsValidationEmploymentByGenderAndRegion = -1; - int columnsValidationActivityStatus = -1; - int columnsValidationHomeownership = -1; - int columnsValidationByGenderAndEducation = -1; - int columnsValidationLabourSupplyByEducation = -1; - if(country.equals(Country.IT)) { - columnsWagesMales = 11; - columnsWagesFemales = 11; - columnsEmploymentSelectionMales = 14; - columnsEmploymentSelectionFemales = 14; - columnsLabourSupplyUtilityMales = 11; - columnsLabourSupplyUtilityFemales = 11; - columnsLabourSupplyUtilityMalesWithDependent = 10; - columnsLabourSupplyUtilityFemalesWithDependent = 9; - columnsLabourSupplyUtilityACMales = 12; - columnsLabourSupplyUtilityACFemales = 9; - columnsLabourSupplyUtilityCouples = 17; - columnsHealthH1a = 15; //1 for coeffs + 15 for var-cov matrix - columnsHealthH1b = 22; - columnsHealthH2b = 24; - columnsHealthHM1 = 6; - columnsHealthHM2Males = 9; - columnsHealthHM2Females = 9; - columnsEducationE1a = 14; - columnsEducationE1b = 19; - columnsEducationE2a = 22; - columnsPartnershipU1 = 21; - columnsPartnershipU2 = 27; - columnsFertilityF1 = 22; - columnsIncomeI1a = 13; - columnsIncomeI1b = 22; - columnsIncomeI3a = 13; - columnsIncomeI3b = 22; - columnsIncomeI3c = 23; - columnsIncomeI3a_selection = 13; - columnsIncomeI3b_selection = 22; - columnsLeaveHomeP1a = 19; - columnsHomeownership = 32; - columnsRetirementR1a = 19; - columnsRetirementR1b = 24; - columnsChildcareC1a = 37; - columnsChildcareC1b = 37; - columnsValidationStudentsByAge = 10; - columnsValidationStudentsByRegion = 6; - columnsValidationEducationLevel = 3; - columnsValidationEducationLevelByAge = 24; - columnsValidationEducationLevelByRegion = 15; - columnsValidationPartneredBUShareByRegion = 6; - columnsValidationDisabledByGender = 6; - columnsValidationDisabledByAgeGroup = 2; - columnsValidationHealthByAgeGroup = 6; - columnsValidationEmploymentByGender = 2; - columnsValidationEmploymentByGenderAndAge = 18; - columnsValidationEmploymentByMaternity = 3; - columnsValidationEmploymentByGenderAndRegion = 10; - columnsValidationActivityStatus = 3; - columnsValidationLabourSupplyByEducation = 3; - } - else if(country.equals(Country.UK)) { - columnsWagesMalesNE = 30; - columnsWagesMalesE = 31; - columnsWagesFemalesNE = 30; - columnsWagesFemalesE = 31; - columnsEmploymentSelectionMalesNE = 30; - columnsEmploymentSelectionMalesE = 29; - columnsEmploymentSelectionFemalesNE = 30; - columnsEmploymentSelectionFemalesE = 29; - columnsLabourSupplyUtilityMales = 19; - columnsLabourSupplyUtilityFemales = 12; - columnsLabourSupplyUtilityMalesWithDependent = 23; - columnsLabourSupplyUtilityFemalesWithDependent = 23; - columnsLabourSupplyUtilityACMales = 17; - columnsLabourSupplyUtilityACFemales = 17; - columnsLabourSupplyUtilityCouples = 64; - columnsLabourCovid19_SE = 1; - columnsLabourCovid19_2a_processes = 1; - columnsHealthH1a = 28; - columnsHealthH1b = 35; - columnsHealthH2b = 35; - columnsHealthHM1 = 31; - columnsHealthHM2Males = 11; - columnsHealthHM2Females = 11; - columnsSocialCareS1a = 17; - columnsSocialCareS1b = 18; - columnsSocialCareS2a = 32; - columnsSocialCareS2b = 32; - columnsSocialCareS2c = 39; - columnsSocialCareS2d = 17; - columnsSocialCareS2e = 16; - columnsSocialCareS2f = 36; - columnsSocialCareS2g = 21; - columnsSocialCareS2h = 21; - columnsSocialCareS2i = 21; - columnsSocialCareS2j = 21; - columnsSocialCareS2k = 18; - columnsSocialCareS3a = 36; - columnsSocialCareS3b = 38; - columnsSocialCareS3c = 37; - columnsSocialCareS3d = 79; - columnsSocialCareS3e = 37; - columnsUnemploymentU1a = 19; - columnsUnemploymentU1b = 19; - columnsUnemploymentU1c = 19; - columnsUnemploymentU1d = 19; - columnsEducationE1a = 19; - columnsEducationE1b = 25; - columnsEducationE2a = 20; - columnsPartnershipU1a = 27; - columnsPartnershipU1b = 31; - columnsPartnershipU2b = 38; - columnsFertilityF1a = 6; - columnsFertilityF1b = 26; - columnsIncomeI1a = 19; //* - columnsIncomeI1b = 31; //* - columnsIncomeI3a = 20; - columnsIncomeI3b = 29; - columnsIncomeI3c = 28; //* - columnsIncomeI4a = 24; //* - columnsIncomeI4b = 25; - columnsIncomeI5a = 25; - columnsIncomeI5b = 25; - columnsIncomeI6a = 22; //* - columnsIncomeI6b = 22; //* - columnsIncomeI3a_selection = 20; - columnsIncomeI3b_selection = 29; - columnsLeaveHomeP1a = 25; - columnsHomeownership = 33; - columnsRetirementR1a = 26; - columnsRetirementR1b = 31; - columnsChildcareC1a = 37; - columnsChildcareC1b = 37; - columnsValidationStudentsByAge = 10; - columnsValidationStudentsByRegion = 13; - columnsValidationEducationLevel = 3; - columnsValidationEducationLevelByAge = 24; - columnsValidationEducationLevelByRegion = 36; - columnsValidationPartneredBUShareByRegion = 13; - columnsValidationDisabledByGender = 2; - columnsValidationDisabledByAgeGroup = 6; - columnsValidationHealthByAgeGroup = 6; - columnsValidationMentalHealthByAgeGroup = 18; - columnsValidationEmploymentByGender = 2; - columnsValidationEmploymentByGenderAndAge = 18; - columnsValidationEmploymentByMaternity = 3; - columnsValidationEmploymentByGenderAndRegion = 24; - columnsValidationActivityStatus = 3; - columnsValidationHomeownership = 1; - columnsValidationLabourSupplyByEducation = 3; - columnsValidationByGenderAndEducation = 6; - } - else throw new IllegalArgumentException("Country not recognised in Parameters.loadParameters()!"); + int columnsWagesMalesNE = 21; //# + int columnsWagesMalesE = 22; //# + int columnsWagesFemalesNE = 21; //# + int columnsWagesFemalesE = 22; //# + int columnsEmploymentSelectionMalesNE = 21; //# + int columnsEmploymentSelectionMalesE = 20; //# + int columnsEmploymentSelectionFemalesNE = 21; //# + int columnsEmploymentSelectionFemalesE = 20; //# + int columnsLabourSupplyUtilityMales = 15; //# + int columnsLabourSupplyUtilityFemales = 15; //# + int columnsLabourSupplyUtilityMalesWithDependent = 15; //# + int columnsLabourSupplyUtilityFemalesWithDependent = 15; //# + int columnsLabourSupplyUtilityACMales = 15; //# + int columnsLabourSupplyUtilityACFemales = 15; //# + int columnsLabourSupplyUtilityCouples = 60; //# + int columnsHealthH1a = 24; //# + int columnsHealthH1b = 95; //# + int columnsHealthH2b = 30; //# + int columnsEducationE1a = 12; //# + int columnsEducationE1b = 17; //# + int columnsEducationE2a = 14; //# + int columnsPartnershipU1a = 9; //# + int columnsPartnershipU1b = 30; //# + int columnsPartnershipU2b = 32; //# + int columnsFertilityF1a = 5; //# + int columnsFertilityF1b = 30; //# + int columnsIncomeI3a_amount = 15; //# + int columnsIncomeI3b_amount = 25; //# + int columnsIncomeI3a_selection = 15; //# + int columnsIncomeI3b_selection = 25; //# + int columnsLeaveHomeP1a = 19; //# + int columnsHomeownership = 33; //# + int columnsRetirementR1a = 23; //# + int columnsRetirementR1b = 29; //# //The Raw maps contain the estimates and covariance matrices, from which we bootstrap at the start of each simulation - //Heckman model employment selection - //coeffCovarianceEmploymentSelectionMales = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_Males", 1, columnsEmploymentSelectionMales); - coeffCovarianceEmploymentSelectionMalesE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_MaleE", 1, columnsEmploymentSelectionMalesE); - coeffCovarianceEmploymentSelectionMalesNE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_MaleNE", 1, columnsEmploymentSelectionMalesNE); - //coeffCovarianceEmploymentSelectionFemales = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_Females", 1, columnsEmploymentSelectionFemales); - coeffCovarianceEmploymentSelectionFemalesE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_FemaleE", 1, columnsEmploymentSelectionFemalesE); - coeffCovarianceEmploymentSelectionFemalesNE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_FemaleNE", 1, columnsEmploymentSelectionFemalesNE); - // Wages - //coeffCovarianceWagesMales = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_Males", 1, columnsWagesMales); coeffCovarianceWagesMalesE = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_MalesE", 1, columnsWagesMalesE); coeffCovarianceWagesMalesNE = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_MalesNE", 1, columnsWagesMalesNE); - //coeffCovarianceWagesFemales = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_Females", 1, columnsWagesFemales); coeffCovarianceWagesFemalesE = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_FemalesE", 1, columnsWagesFemalesE); coeffCovarianceWagesFemalesNE = ExcelAssistant.loadCoefficientMap("input/reg_wages.xlsx", countryString + "_Wages_FemalesNE", 1, columnsWagesFemalesNE); - //Labour Supply coefficients from Zhechun's estimates on the EM input data + //Labour Supply utility function coefficients coeffLabourSupplyUtilityMales = ExcelAssistant.loadCoefficientMap("input/reg_labourSupplyUtility.xlsx", countryString + "_Single_Males", 1, columnsLabourSupplyUtilityMales); coeffLabourSupplyUtilityFemales = ExcelAssistant.loadCoefficientMap("input/reg_labourSupplyUtility.xlsx", countryString + "_Single_Females", 1, columnsLabourSupplyUtilityFemales); coeffLabourSupplyUtilityMalesWithDependent = ExcelAssistant.loadCoefficientMap("input/reg_labourSupplyUtility.xlsx", countryString + "_Males_With_Dep", 1, columnsLabourSupplyUtilityMalesWithDependent); @@ -1171,145 +1059,37 @@ else if(country.equals(Country.UK)) { coeffLabourSupplyUtilityACFemales = ExcelAssistant.loadCoefficientMap("input/reg_labourSupplyUtility.xlsx", countryString + "_SingleAC_Females", 1, columnsLabourSupplyUtilityACFemales); coeffLabourSupplyUtilityCouples = ExcelAssistant.loadCoefficientMap("input/reg_labourSupplyUtility.xlsx", countryString + "_Couples", 1, columnsLabourSupplyUtilityCouples); - // Load coefficients for Covid-19 labour supply models - // Coefficients for process assigning simulated people to self-employment - coeffCovarianceC19LS_SE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_SE", 1, columnsLabourCovid19_SE); - // Transitions from lagged state: employed - coeffC19LS_E1_NE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E1_NE", 1, 1); - coeffC19LS_E1_SE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E1_SE", 1, 1); - coeffC19LS_E1_FF = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E1_FF", 1, 1); - coeffC19LS_E1_FX = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E1_FX", 1, 1); - coeffC19LS_E1_SC = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E1_SC", 1, 1); - // Transitions from lagged state: furloughed full - coeffC19LS_FF1_E = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FF1_E", 1, 1); - coeffC19LS_FF1_FX = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FF1_FX", 1, 1); - coeffC19LS_FF1_NE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FF1_NE", 1, 1); - coeffC19LS_FF1_SE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FF1_SE", 1, 1); - // Transitions from lagged state: furloughed flex - coeffC19LS_FX1_E = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FX1_E", 1, 1); - coeffC19LS_FX1_FF = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FX1_FF", 1, 1); - coeffC19LS_FX1_NE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FX1_NE", 1, 1); - coeffC19LS_FX1_SE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_FX1_SE", 1, 1); - // Transitions from lagged state: self-employed - coeffC19LS_S1_E = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_S1_E", 1, 1); - coeffC19LS_S1_NE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_S1_NE", 1, 1); - // Transitions from lagged state: not-employed - coeffC19LS_U1_E = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_U1_E", 1, 1); - coeffC19LS_U1_SE = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_U1_SE", 1, 1); - - // For multi logit regressions, put coefficients loaded below into maps - coeffC19LS_E1Map = new LinkedHashMap<>(); //Add only categories from Les_transitions_E1 enum which are possible destinations for transitions from employment - coeffC19LS_E1Map.put(Les_transitions_E1.NotEmployed, coeffC19LS_E1_NE); - coeffC19LS_E1Map.put(Les_transitions_E1.SelfEmployed, coeffC19LS_E1_SE); - coeffC19LS_E1Map.put(Les_transitions_E1.FurloughedFull, coeffC19LS_E1_FF); - coeffC19LS_E1Map.put(Les_transitions_E1.FurloughedFlex, coeffC19LS_E1_FX); - coeffC19LS_E1Map.put(Les_transitions_E1.SomeChanges, coeffC19LS_E1_SC); - - coeffC19LS_FF1Map = new LinkedHashMap<>(); //Add only categories from Les_transitions_FF1 enum which are possible destinations for transitions from furlough full - coeffC19LS_FF1Map.put(Les_transitions_FF1.Employee, coeffC19LS_FF1_E); - coeffC19LS_FF1Map.put(Les_transitions_FF1.FurloughedFlex, coeffC19LS_FF1_FX); - coeffC19LS_FF1Map.put(Les_transitions_FF1.NotEmployed, coeffC19LS_FF1_NE); - coeffC19LS_FF1Map.put(Les_transitions_FF1.SelfEmployed, coeffC19LS_FF1_SE); - - coeffC19LS_FX1Map = new LinkedHashMap<>(); //Add only categories from Les_transitions_FF1 enum which are possible destinations for transitions from furlough flex - coeffC19LS_FX1Map.put(Les_transitions_FX1.Employee, coeffC19LS_FX1_E); - coeffC19LS_FX1Map.put(Les_transitions_FX1.FurloughedFull, coeffC19LS_FX1_FF); - coeffC19LS_FX1Map.put(Les_transitions_FX1.NotEmployed, coeffC19LS_FX1_NE); - coeffC19LS_FX1Map.put(Les_transitions_FX1.SelfEmployed, coeffC19LS_FX1_SE); - - coeffC19LS_S1Map = new LinkedHashMap<>(); //Add only categories from Les_transitions_S1 enum which are possible destinations for transitions from self-employment - coeffC19LS_S1Map.put(Les_transitions_S1.Employee, coeffC19LS_S1_E); - coeffC19LS_S1Map.put(Les_transitions_S1.NotEmployed, coeffC19LS_S1_NE); - - coeffC19LS_U1Map = new LinkedHashMap<>(); //Add only categories from Les_transitions_U1 enum which are possible destinations for transitions from non-employment - coeffC19LS_U1Map.put(Les_transitions_U1.Employee, coeffC19LS_U1_E); - coeffC19LS_U1Map.put(Les_transitions_U1.SelfEmployed, coeffC19LS_U1_SE); - - // Coefficients for new working hours - coeffC19LS_E2a = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E2a", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_E2b = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_E2b", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_F2a = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_F2a", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_F2b = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_F2b", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_F2c = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_F2c", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_S2a = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_S2a", 1, columnsLabourCovid19_2a_processes); - coeffC19LS_U2a = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_U2a", 1, columnsLabourCovid19_2a_processes); - - // Coefficients for probability of SEISS - coeffC19LS_S3 = ExcelAssistant.loadCoefficientMap("input/reg_labourCovid19.xlsx", countryString + "_C19LS_S3", 1, 1); + //Heckman model employment selection + coeffCovarianceEmploymentSelectionMalesE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_MaleE", 1, columnsEmploymentSelectionMalesE); + coeffCovarianceEmploymentSelectionMalesNE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_MaleNE", 1, columnsEmploymentSelectionMalesNE); + coeffCovarianceEmploymentSelectionFemalesE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_FemaleE", 1, columnsEmploymentSelectionFemalesE); + coeffCovarianceEmploymentSelectionFemalesNE = ExcelAssistant.loadCoefficientMap("input/reg_employmentSelection.xlsx", countryString + "_EmploymentSelection_FemaleNE", 1, columnsEmploymentSelectionFemalesNE); //Health coeffCovarianceHealthH1a = ExcelAssistant.loadCoefficientMap("input/reg_health.xlsx", countryString + "_H1a", 1, columnsHealthH1a); coeffCovarianceHealthH1b = ExcelAssistant.loadCoefficientMap("input/reg_health.xlsx", countryString + "_H1b", 1, columnsHealthH1b); coeffCovarianceHealthH2b = ExcelAssistant.loadCoefficientMap("input/reg_health.xlsx", countryString + "_H2b", 1, columnsHealthH2b); - //Social care - coeffCovarianceSocialCareS1a = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S1a", 1, columnsSocialCareS1a); - coeffCovarianceSocialCareS1b = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S1b", 1, columnsSocialCareS1b); - coeffCovarianceSocialCareS2a = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2a", 1, columnsSocialCareS2a); - coeffCovarianceSocialCareS2b = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2b", 1, columnsSocialCareS2b); - coeffCovarianceSocialCareS2c = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2c", 1, columnsSocialCareS2c); - coeffCovarianceSocialCareS2d = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2d", 1, columnsSocialCareS2d); - coeffCovarianceSocialCareS2e = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2e", 1, columnsSocialCareS2e); - coeffCovarianceSocialCareS2f = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2f", 1, columnsSocialCareS2f); - coeffCovarianceSocialCareS2g = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2g", 1, columnsSocialCareS2g); - coeffCovarianceSocialCareS2h = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2h", 1, columnsSocialCareS2h); - coeffCovarianceSocialCareS2i = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2i", 1, columnsSocialCareS2i); - coeffCovarianceSocialCareS2j = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2j", 1, columnsSocialCareS2j); - coeffCovarianceSocialCareS2k = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S2k", 1, columnsSocialCareS2k); - coeffCovarianceSocialCareS3a = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S3a", 1, columnsSocialCareS3a); - coeffCovarianceSocialCareS3b = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S3b", 1, columnsSocialCareS3b); - coeffCovarianceSocialCareS3c = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S3c", 1, columnsSocialCareS3c); - coeffCovarianceSocialCareS3d = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S3d", 1, columnsSocialCareS3d); - coeffCovarianceSocialCareS3e = ExcelAssistant.loadCoefficientMap("input/reg_socialcare.xlsx", countryString + "_S3e", 1, columnsSocialCareS3e); - - //Unemployment - coeffCovarianceUnemploymentU1a = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_U1a", 1, columnsUnemploymentU1a); - coeffCovarianceUnemploymentU1b = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_U1b", 1, columnsUnemploymentU1b); - coeffCovarianceUnemploymentU1c = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_U1c", 1, columnsUnemploymentU1c); - coeffCovarianceUnemploymentU1d = ExcelAssistant.loadCoefficientMap("input/reg_unemployment.xlsx", countryString + "_U1d", 1, columnsUnemploymentU1d); - - //Health mental: level and case-based - coeffCovarianceHM1Level = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM1_L", 1, columnsHealthHM1); - coeffCovarianceHM2LevelMales = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM2_Males_L", 1, columnsHealthHM2Males); - coeffCovarianceHM2LevelFemales = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM2_Females_L", 1, columnsHealthHM2Females); - coeffCovarianceHM1Case = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM1_C", 1, columnsHealthHM1); - coeffCovarianceHM2CaseMales = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM2_Males_C", 1, columnsHealthHM2Males); - coeffCovarianceHM2CaseFemales = ExcelAssistant.loadCoefficientMap("input/reg_health_mental.xlsx", countryString + "_HM2_Females_C", 1, columnsHealthHM2Females); - //Education coeffCovarianceEducationE1a = ExcelAssistant.loadCoefficientMap("input/reg_education.xlsx", countryString + "_E1a", 1, columnsEducationE1a); coeffCovarianceEducationE1b = ExcelAssistant.loadCoefficientMap("input/reg_education.xlsx", countryString + "_E1b", 1, columnsEducationE1b); coeffCovarianceEducationE2a = ExcelAssistant.loadCoefficientMap("input/reg_education.xlsx", countryString + "_E2a", 1, columnsEducationE2a); //Partnership - if (country.equals(Country.UK)) { - coeffCovariancePartnershipU1a = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U1a", 1, columnsPartnershipU1a); - coeffCovariancePartnershipU1b = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U1b", 1, columnsPartnershipU1b); - coeffCovariancePartnershipU2b = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U2b", 1, columnsPartnershipU2b); - } - else if (country.equals(Country.IT)) { - coeffCovariancePartnershipITU1 = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U1", 1, columnsPartnershipU1); - coeffCovariancePartnershipITU2 = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U2", 1, columnsPartnershipU2); - } + coeffCovariancePartnershipU1a = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U1a", 1, columnsPartnershipU1a); + coeffCovariancePartnershipU1b = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U1b", 1, columnsPartnershipU1b); + coeffCovariancePartnershipU2b = ExcelAssistant.loadCoefficientMap("input/reg_partnership.xlsx", countryString + "_U2b", 1, columnsPartnershipU2b); //Partnership - parameters for matching based on wage and age differential meanCovarianceParametricMatching = ExcelAssistant.loadCoefficientMap("input/scenario_parametricMatching.xlsx", countryString, 1, 1); //Fertility - if (country.equals(Country.UK)) { - coeffCovarianceFertilityF1a = ExcelAssistant.loadCoefficientMap("input/reg_fertility.xlsx", countryString + "_F1a", 1, columnsFertilityF1a); - coeffCovarianceFertilityF1b = ExcelAssistant.loadCoefficientMap("input/reg_fertility.xlsx", countryString + "_F1b", 1, columnsFertilityF1b); - } - else if (country.equals(Country.IT)) { - coeffCovarianceFertilityF1 = ExcelAssistant.loadCoefficientMap("input/reg_fertility.xlsx", countryString + "_F1", 1, columnsFertilityF1); - } + coeffCovarianceFertilityF1a = ExcelAssistant.loadCoefficientMap("input/reg_fertility.xlsx", countryString + "_F1a", 1, columnsFertilityF1a); + coeffCovarianceFertilityF1b = ExcelAssistant.loadCoefficientMap("input/reg_fertility.xlsx", countryString + "_F1b", 1, columnsFertilityF1b); //Income - coeffCovarianceIncomeI3a = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3a", 1, columnsIncomeI3a); - coeffCovarianceIncomeI3b = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3b", 1, columnsIncomeI3b); - coeffCovarianceIncomeI4b = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I4b", 1, columnsIncomeI4b); - coeffCovarianceIncomeI5a_selection = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I5a", 1, columnsIncomeI5a); - coeffCovarianceIncomeI5b_amount = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I5b", 1, columnsIncomeI5b); + coeffCovarianceIncomeI3a_amount = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3a_amount", 1, columnsIncomeI3a_amount); + coeffCovarianceIncomeI3b_amount = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3b_amount", 1, columnsIncomeI3b_amount); coeffCovarianceIncomeI3a_selection = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3a_selection", 1, columnsIncomeI3a_selection); coeffCovarianceIncomeI3b_selection = ExcelAssistant.loadCoefficientMap("input/reg_income.xlsx", countryString + "_I3b_selection", 1, columnsIncomeI3b_selection); @@ -1323,30 +1103,24 @@ else if (country.equals(Country.IT)) { coeffCovarianceRetirementR1a = ExcelAssistant.loadCoefficientMap("input/reg_retirement.xlsx", countryString + "_R1a", 1, columnsRetirementR1a); coeffCovarianceRetirementR1b = ExcelAssistant.loadCoefficientMap("input/reg_retirement.xlsx", countryString + "_R1b", 1, columnsRetirementR1b); - //Childcare - coeffCovarianceChildcareC1a = ExcelAssistant.loadCoefficientMap("input/reg_childcarecost.xlsx", countryString + "_C1a", 1, columnsChildcareC1a); - coeffCovarianceChildcareC1b = ExcelAssistant.loadCoefficientMap("input/reg_childcarecost.xlsx", countryString + "_C1b", 1, columnsChildcareC1b); //Bootstrap the coefficients if(bootstrapAll) { //Wages - //coeffCovarianceWagesMales = RegressionUtils.bootstrap(coeffCovarianceWagesMales); coeffCovarianceWagesMalesE = RegressionUtils.bootstrap(coeffCovarianceWagesMalesE); coeffCovarianceWagesMalesNE = RegressionUtils.bootstrap(coeffCovarianceWagesMalesNE); - //coeffCovarianceWagesFemales = RegressionUtils.bootstrap(coeffCovarianceWagesFemales); coeffCovarianceWagesFemalesE = RegressionUtils.bootstrap(coeffCovarianceWagesFemalesE); coeffCovarianceWagesFemalesNE = RegressionUtils.bootstrap(coeffCovarianceWagesFemalesNE); //Employment selection - //coeffCovarianceEmploymentSelectionMales = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionMales); coeffCovarianceEmploymentSelectionMalesE = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionMalesE); coeffCovarianceEmploymentSelectionMalesNE = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionMalesNE); - //coeffCovarianceEmploymentSelectionFemales = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionFemales); coeffCovarianceEmploymentSelectionFemalesE = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionFemalesE); coeffCovarianceEmploymentSelectionFemalesNE = RegressionUtils.bootstrap(coeffCovarianceEmploymentSelectionFemalesNE); //Labour supply utility + /* coeffLabourSupplyUtilityMales = RegressionUtils.bootstrap(coeffLabourSupplyUtilityMales); coeffLabourSupplyUtilityFemales = RegressionUtils.bootstrap(coeffLabourSupplyUtilityFemales); coeffLabourSupplyUtilityMalesWithDependent = RegressionUtils.bootstrap(coeffLabourSupplyUtilityMalesWithDependent); @@ -1354,6 +1128,7 @@ else if (country.equals(Country.IT)) { coeffLabourSupplyUtilityACMales = RegressionUtils.bootstrap(coeffLabourSupplyUtilityACMales); coeffLabourSupplyUtilityACFemales = RegressionUtils.bootstrap(coeffLabourSupplyUtilityACFemales); coeffLabourSupplyUtilityCouples = RegressionUtils.bootstrap(coeffLabourSupplyUtilityCouples); + */ //Education coeffCovarianceEducationE1a = RegressionUtils.bootstrap(coeffCovarianceEducationE1a); @@ -1364,51 +1139,11 @@ else if (country.equals(Country.IT)) { coeffCovarianceHealthH1a = RegressionUtils.bootstrap(coeffCovarianceHealthH1a); //Note that this overrides the original coefficient map with bootstrapped values coeffCovarianceHealthH1b = RegressionUtils.bootstrap(coeffCovarianceHealthH1b); coeffCovarianceHealthH2b = RegressionUtils.bootstrap(coeffCovarianceHealthH2b); - coeffCovarianceHM1Level = RegressionUtils.bootstrap(coeffCovarianceHM1Level); - coeffCovarianceHM2LevelMales = RegressionUtils.bootstrap(coeffCovarianceHM2LevelMales); - coeffCovarianceHM2LevelFemales = RegressionUtils.bootstrap(coeffCovarianceHM2LevelFemales); - coeffCovarianceHM1Case = RegressionUtils.bootstrap(coeffCovarianceHM1Case); - coeffCovarianceHM2CaseMales = RegressionUtils.bootstrap(coeffCovarianceHM2CaseMales); - coeffCovarianceHM2CaseFemales = RegressionUtils.bootstrap(coeffCovarianceHM2CaseFemales); - - //Social care - coeffCovarianceSocialCareS1a = RegressionUtils.bootstrap(coeffCovarianceSocialCareS1a); - coeffCovarianceSocialCareS1b = RegressionUtils.bootstrap(coeffCovarianceSocialCareS1b); - coeffCovarianceSocialCareS2a = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2a); - coeffCovarianceSocialCareS2b = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2b); - coeffCovarianceSocialCareS2c = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2c); - coeffCovarianceSocialCareS2d = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2d); - coeffCovarianceSocialCareS2e = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2e); - coeffCovarianceSocialCareS2f = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2f); - coeffCovarianceSocialCareS2g = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2g); - coeffCovarianceSocialCareS2h = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2h); - coeffCovarianceSocialCareS2i = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2i); - coeffCovarianceSocialCareS2j = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2j); - coeffCovarianceSocialCareS2k = RegressionUtils.bootstrap(coeffCovarianceSocialCareS2k); - coeffCovarianceSocialCareS3a = RegressionUtils.bootstrap(coeffCovarianceSocialCareS3a); - coeffCovarianceSocialCareS3b = RegressionUtils.bootstrap(coeffCovarianceSocialCareS3b); - coeffCovarianceSocialCareS3c = RegressionUtils.bootstrap(coeffCovarianceSocialCareS3c); - coeffCovarianceSocialCareS3d = RegressionUtils.bootstrap(coeffCovarianceSocialCareS3d); - coeffCovarianceSocialCareS3e = RegressionUtils.bootstrap(coeffCovarianceSocialCareS3e); - - //Unemployment - coeffCovarianceUnemploymentU1a = RegressionUtils.bootstrap(coeffCovarianceUnemploymentU1a); - coeffCovarianceUnemploymentU1b = RegressionUtils.bootstrap(coeffCovarianceUnemploymentU1b); - coeffCovarianceUnemploymentU1c = RegressionUtils.bootstrap(coeffCovarianceUnemploymentU1c); - coeffCovarianceUnemploymentU1d = RegressionUtils.bootstrap(coeffCovarianceUnemploymentU1d); //Non-labour income - // coeffCovarianceIncomeI1a = RegressionUtils.bootstrap(coeffCovarianceIncomeI1a); // Commented out as not used any more since income is split. - // coeffCovarianceIncomeI1b = RegressionUtils.bootstrap(coeffCovarianceIncomeI1b); // Commented out as not used any more since income is split. - coeffCovarianceIncomeI3a = RegressionUtils.bootstrap(coeffCovarianceIncomeI3a); - coeffCovarianceIncomeI3b = RegressionUtils.bootstrap(coeffCovarianceIncomeI3b); - //coeffCovarianceIncomeI3c = RegressionUtils.bootstrap(coeffCovarianceIncomeI3c); - //coeffCovarianceIncomeI4a = RegressionUtils.bootstrap(coeffCovarianceIncomeI4a); - coeffCovarianceIncomeI4b = RegressionUtils.bootstrap(coeffCovarianceIncomeI4b); - coeffCovarianceIncomeI5a_selection = RegressionUtils.bootstrap(coeffCovarianceIncomeI5a_selection); - coeffCovarianceIncomeI5b_amount = RegressionUtils.bootstrap(coeffCovarianceIncomeI5b_amount); - //coeffCovarianceIncomeI6a_selection = RegressionUtils.bootstrap(coeffCovarianceIncomeI6a_selection); - //coeffCovarianceIncomeI6b_amount = RegressionUtils.bootstrap(coeffCovarianceIncomeI6b_amount); + + coeffCovarianceIncomeI3a_amount = RegressionUtils.bootstrap(coeffCovarianceIncomeI3a_amount); + coeffCovarianceIncomeI3b_amount = RegressionUtils.bootstrap(coeffCovarianceIncomeI3b_amount); coeffCovarianceIncomeI3a_selection = RegressionUtils.bootstrap(coeffCovarianceIncomeI3a_selection); coeffCovarianceIncomeI3b_selection = RegressionUtils.bootstrap(coeffCovarianceIncomeI3b_selection); @@ -1422,123 +1157,66 @@ else if (country.equals(Country.IT)) { coeffCovarianceRetirementR1a = RegressionUtils.bootstrap(coeffCovarianceRetirementR1a); coeffCovarianceRetirementR1b = RegressionUtils.bootstrap(coeffCovarianceRetirementR1b); - //Childcare - coeffCovarianceChildcareC1a = RegressionUtils.bootstrap(coeffCovarianceChildcareC1a); - coeffCovarianceChildcareC1b = RegressionUtils.bootstrap(coeffCovarianceChildcareC1b); //Specification of some processes depends on the country: - if (country.equals(Country.UK)) { - coeffCovariancePartnershipU1a = RegressionUtils.bootstrap(coeffCovariancePartnershipU1a); - coeffCovariancePartnershipU1b = RegressionUtils.bootstrap(coeffCovariancePartnershipU1b); - coeffCovariancePartnershipU2b = RegressionUtils.bootstrap(coeffCovariancePartnershipU2b); - coeffCovarianceFertilityF1a = RegressionUtils.bootstrap(coeffCovarianceFertilityF1a); - coeffCovarianceFertilityF1b = RegressionUtils.bootstrap(coeffCovarianceFertilityF1b); - } else if (country.equals(Country.IT)) { - coeffCovariancePartnershipITU1 = RegressionUtils.bootstrap(coeffCovariancePartnershipITU1); - coeffCovariancePartnershipITU2 = RegressionUtils.bootstrap(coeffCovariancePartnershipITU2); - coeffCovarianceFertilityF1 = RegressionUtils.bootstrap(coeffCovarianceFertilityF1); - } + coeffCovariancePartnershipU1a = RegressionUtils.bootstrap(coeffCovariancePartnershipU1a); + coeffCovariancePartnershipU1b = RegressionUtils.bootstrap(coeffCovariancePartnershipU1b); + coeffCovariancePartnershipU2b = RegressionUtils.bootstrap(coeffCovariancePartnershipU2b); + coeffCovarianceFertilityF1a = RegressionUtils.bootstrap(coeffCovarianceFertilityF1a); + coeffCovarianceFertilityF1b = RegressionUtils.bootstrap(coeffCovarianceFertilityF1b); + } + // Define regression objects + + + //Health - regHealthH1a = new OrderedProbitRegression(coeffCovarianceHealthH1a, Dhe.class); - regHealthH1b = new OrderedProbitRegression(coeffCovarianceHealthH1b, Dhe.class); - regHealthH2b = new ProbitRegression(coeffCovarianceHealthH2b); - - //Social care - coeffCovarianceSocialCareS2cMap = MultiLogitRegression.populateMultinomialCoefficientMap(SocialCareReceiptS2c.class, coeffCovarianceSocialCareS2c); - coeffCovarianceSocialCareS2eMap = MultiLogitRegression.populateMultinomialCoefficientMap(PartnerSupplementaryCarer.class, coeffCovarianceSocialCareS2e); - coeffCovarianceSocialCareS2fMap = MultiLogitRegression.populateMultinomialCoefficientMap(NotPartnerInformalCarer.class, coeffCovarianceSocialCareS2f); - coeffCovarianceSocialCareS3dMap = MultiLogitRegression.populateMultinomialCoefficientMap(SocialCareProvision.class, coeffCovarianceSocialCareS3d); - regReceiveCareS1a = new ProbitRegression(coeffCovarianceSocialCareS1a); - regCareHoursS1b = new ProbitRegression(coeffCovarianceSocialCareS1b); - regNeedCareS2a = new ProbitRegression(coeffCovarianceSocialCareS2a); - regReceiveCareS2b = new ProbitRegression(coeffCovarianceSocialCareS2b); - regSocialCareMarketS2c = new MultiLogitRegression<>(SocialCareReceiptS2c.class, coeffCovarianceSocialCareS2cMap); - regReceiveCarePartnerS2d = new ProbitRegression(coeffCovarianceSocialCareS2d); - regPartnerSupplementaryCareS2e = new MultiLogitRegression<>(PartnerSupplementaryCarer.class, coeffCovarianceSocialCareS2eMap); - regNotPartnerInformalCareS2f = new MultiLogitRegression<>(NotPartnerInformalCarer.class, coeffCovarianceSocialCareS2fMap); - regPartnerCareHoursS2g = new LinearRegression(coeffCovarianceSocialCareS2g); - regDaughterCareHoursS2h = new LinearRegression(coeffCovarianceSocialCareS2h); - regSonCareHoursS2i = new LinearRegression(coeffCovarianceSocialCareS2i); - regOtherCareHoursS2j = new LinearRegression(coeffCovarianceSocialCareS2j); - regFormalCareHoursS2k = new LinearRegression(coeffCovarianceSocialCareS2k); - regCarePartnerProvCareToOtherS3a = new ProbitRegression(coeffCovarianceSocialCareS3a); - regNoCarePartnerProvCareToOtherS3b = new ProbitRegression(coeffCovarianceSocialCareS3b); - regNoPartnerProvCareToOtherS3c = new ProbitRegression(coeffCovarianceSocialCareS3c); - regInformalCareToS3d = new MultiLogitRegression<>(SocialCareProvision.class, coeffCovarianceSocialCareS3dMap); - regCareHoursProvS3e = new LinearRegression(coeffCovarianceSocialCareS3e); - - //Unemployment - regUnemploymentMaleGraduateU1a = new ProbitRegression(coeffCovarianceUnemploymentU1a); - regUnemploymentMaleNonGraduateU1b = new ProbitRegression(coeffCovarianceUnemploymentU1b); - regUnemploymentFemaleGraduateU1c = new ProbitRegression(coeffCovarianceUnemploymentU1c); - regUnemploymentFemaleNonGraduateU1d = new ProbitRegression(coeffCovarianceUnemploymentU1d); - - //Health mental - regHealthHM1Level = new LinearRegression(coeffCovarianceHM1Level); - regHealthHM2LevelMales = new LinearRegression(coeffCovarianceHM2LevelMales); - regHealthHM2LevelFemales = new LinearRegression(coeffCovarianceHM2LevelFemales); - - regHealthHM1Case = new LogitRegression(coeffCovarianceHM1Case); - regHealthHM2CaseMales = new LogitRegression(coeffCovarianceHM2CaseMales); - regHealthHM2CaseFemales = new LogitRegression(coeffCovarianceHM2CaseFemales); + regHealthH1a = new GeneralisedOrderedRegression<>(RegressionType.GenOrderedLogit, Dhe.class, coeffCovarianceHealthH1a); + regHealthH1b = new GeneralisedOrderedRegression<>(RegressionType.GenOrderedLogit, Dhe.class, coeffCovarianceHealthH1b); + MultiKeyCoefficientMap coeffHealthH2bAppended = appendCoefficientMaps(coeffCovarianceHealthH2b, disabilityTimeAdjustment, "Year"); + regHealthH2b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffHealthH2bAppended); //Education - regEducationE1a = new ProbitRegression(coeffCovarianceEducationE1a); - regEducationE1b = new ProbitRegression(coeffCovarianceEducationE1b); - regEducationE2a = new OrderedProbitRegression(coeffCovarianceEducationE2a, Education.class); + MultiKeyCoefficientMap coeffEducationE1aAppended = appendCoefficientMaps(coeffCovarianceEducationE1a, studentsTimeAdjustment, "Year"); + MultiKeyCoefficientMap coeffEducationE1bAppended = appendCoefficientMaps(coeffCovarianceEducationE1b, studentsTimeAdjustment, "Year"); + regEducationE1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffEducationE1aAppended); + regEducationE1b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffEducationE1bAppended); + regEducationE2a = new GeneralisedOrderedRegression(RegressionType.GenOrderedLogit, Education.class, coeffCovarianceEducationE2a); //Partnership - if (country.equals(Country.UK)) { - regPartnershipU1a = new ProbitRegression(coeffCovariancePartnershipU1a); - regPartnershipU1b = new ProbitRegression(coeffCovariancePartnershipU1b); - regPartnershipU2b = new ProbitRegression(coeffCovariancePartnershipU2b); - } else if (country.equals(Country.IT)) { - regPartnershipITU1 = new ProbitRegression(coeffCovariancePartnershipITU1); - regPartnershipITU2 = new ProbitRegression(coeffCovariancePartnershipITU2); - } + MultiKeyCoefficientMap coeffPartnershipU1aAppended = appendCoefficientMaps(coeffCovariancePartnershipU1a, partnershipTimeAdjustment, "Year"); + MultiKeyCoefficientMap coeffPartnershipU1bAppended = appendCoefficientMaps(coeffCovariancePartnershipU1b, partnershipTimeAdjustment, "Year"); + MultiKeyCoefficientMap coeffPartnershipU2bAppended = appendCoefficientMaps(coeffCovariancePartnershipU2b, partnershipTimeAdjustment, "Year", true); + regPartnershipU1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffPartnershipU1aAppended); + regPartnershipU1b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffPartnershipU1bAppended); + regPartnershipU2b = new BinomialRegression(RegressionType.Probit, ReversedIndicator.class, coeffPartnershipU2bAppended); //Fertility - if (country.equals(Country.UK)) { - regFertilityF1a = new ProbitRegression(coeffCovarianceFertilityF1a); - regFertilityF1b = new ProbitRegression(coeffCovarianceFertilityF1b); - } else if (country.equals(Country.IT)) { - regFertilityF1 = new ProbitRegression(coeffCovarianceFertilityF1); - } + MultiKeyCoefficientMap coeffFertilityF1aAppended = appendCoefficientMaps(coeffCovarianceFertilityF1a, fertilityTimeAdjustment, "Year"); + MultiKeyCoefficientMap coeffFertilityF1bAppended = appendCoefficientMaps(coeffCovarianceFertilityF1b, fertilityTimeAdjustment, "Year"); + regFertilityF1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffFertilityF1aAppended); + regFertilityF1b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffFertilityF1bAppended); //Income - //regIncomeI1a = new LinearRegression(coeffCovarianceIncomeI1a); - //regIncomeI1b = new LinearRegression(coeffCovarianceIncomeI1b); - regIncomeI3a = new LinearRegression(coeffCovarianceIncomeI3a); - regIncomeI3b = new LinearRegression(coeffCovarianceIncomeI3b); - //regIncomeI3c = new LinearRegression(coeffCovarianceIncomeI3c); - //regIncomeI4a = new LinearRegression(coeffCovarianceIncomeI4a); - regIncomeI4b = new LinearRegression(coeffCovarianceIncomeI4b); - regIncomeI5b_amount = new LinearRegression(coeffCovarianceIncomeI5b_amount); - //regIncomeI6b_amount = new LinearRegression(coeffCovarianceIncomeI6b_amount); - regIncomeI3a_selection = new LogitRegression(coeffCovarianceIncomeI3a_selection); - regIncomeI3b_selection = new LogitRegression(coeffCovarianceIncomeI3b_selection); - regIncomeI5a_selection = new LogitRegression(coeffCovarianceIncomeI5a_selection); - //regIncomeI6a_selection = new LogitRegression(coeffCovarianceIncomeI6a_selection); + regIncomeI3a = new LinearRegression(coeffCovarianceIncomeI3a_amount); + regIncomeI3b = new LinearRegression(coeffCovarianceIncomeI3b_amount); + regIncomeI3a_selection = new BinomialRegression(RegressionType.Logit, Indicator.class, coeffCovarianceIncomeI3a_selection); + regIncomeI3b_selection = new BinomialRegression(RegressionType.Logit, Indicator.class, coeffCovarianceIncomeI3b_selection); //Homeownership - regHomeownershipHO1a = new ProbitRegression(coeffCovarianceHomeownership); + regHomeownershipHO1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffCovarianceHomeownership); //XXX: Note: the model used for selection in Heckman procedure is a Probit, but to obtain Inverse Mills Ratio, linear prediction needs to be obtained - so linear regression used here - //regEmploymentSelectionMale = new LinearRegression(coeffCovarianceEmploymentSelectionMales); regEmploymentSelectionMaleE = new LinearRegression(coeffCovarianceEmploymentSelectionMalesE); regEmploymentSelectionMaleNE = new LinearRegression(coeffCovarianceEmploymentSelectionMalesNE); - //regEmploymentSelectionFemale = new LinearRegression(coeffCovarianceEmploymentSelectionFemales); regEmploymentSelectionFemaleE = new LinearRegression(coeffCovarianceEmploymentSelectionFemalesE); regEmploymentSelectionFemaleNE = new LinearRegression(coeffCovarianceEmploymentSelectionFemalesNE); standardNormalDistribution = new NormalDistribution(); //Wages - //regWagesMales = new LinearRegression(coeffCovarianceWagesMales); regWagesMalesE = new LinearRegression(coeffCovarianceWagesMalesE); regWagesMalesNE = new LinearRegression(coeffCovarianceWagesMalesNE); - //regWagesFemales = new LinearRegression(coeffCovarianceWagesFemales); regWagesFemalesE = new LinearRegression(coeffCovarianceWagesFemalesE); regWagesFemalesNE = new LinearRegression(coeffCovarianceWagesFemalesNE); @@ -1551,32 +1229,14 @@ else if (country.equals(Country.IT)) { regLabourSupplyUtilityACFemales = new LinearRegression(coeffLabourSupplyUtilityACFemales); regLabourSupplyUtilityCouples = new LinearRegression(coeffLabourSupplyUtilityCouples); - // Regressions for Covid-19 labour transition models below - regC19LS_SE = new ProbitRegression(coeffCovarianceC19LS_SE); - regC19LS_E1 = new MultiLogitRegression<>(coeffC19LS_E1Map); - regC19LS_FF1 = new MultiLogitRegression<>(coeffC19LS_FF1Map); - regC19LS_FX1 = new MultiLogitRegression<>(coeffC19LS_FX1Map); - regC19LS_S1 = new MultiLogitRegression<>(coeffC19LS_S1Map); - regC19LS_U1 = new MultiLogitRegression<>(coeffC19LS_U1Map); - regC19LS_E2a = new LinearRegression(coeffC19LS_E2a); - regC19LS_E2b = new LinearRegression(coeffC19LS_E2b); - regC19LS_F2a = new LinearRegression(coeffC19LS_F2a); - regC19LS_F2b = new LinearRegression(coeffC19LS_F2b); - regC19LS_F2c = new LinearRegression(coeffC19LS_F2c); - regC19LS_S2a = new LinearRegression(coeffC19LS_S2a); - regC19LS_U2a = new LinearRegression(coeffC19LS_U2a); - regC19LS_S3 = new LogitRegression(coeffC19LS_S3); - //Leaving parental home - regLeaveHomeP1a = new ProbitRegression(coeffCovarianceLeaveHomeP1a); + regLeaveHomeP1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffCovarianceLeaveHomeP1a); //Retirement - regRetirementR1a = new ProbitRegression(coeffCovarianceRetirementR1a); - regRetirementR1b = new ProbitRegression(coeffCovarianceRetirementR1b); - - //Childcare - regChildcareC1a = new ProbitRegression(coeffCovarianceChildcareC1a); - regChildcareC1b = new LinearRegression(coeffCovarianceChildcareC1b); + MultiKeyCoefficientMap coeffRetirementR1aAppended = appendCoefficientMaps(coeffCovarianceRetirementR1a, retirementTimeAdjustment, "Year"); + MultiKeyCoefficientMap coeffRetirementR1bAppended = appendCoefficientMaps(coeffCovarianceRetirementR1b, retirementTimeAdjustment, "Year"); + regRetirementR1a = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffRetirementR1aAppended); + regRetirementR1b = new BinomialRegression(RegressionType.Probit, Indicator.class, coeffRetirementR1bAppended); //Create the age and wage differential MultivariateNormalDistribution for partnership formation, using means and var-cov matrix loaded from Excel targetMeanAgeDifferential = ((Number) meanCovarianceParametricMatching.getValue("mean_dag_diff")).doubleValue(); @@ -1588,71 +1248,6 @@ else if (country.equals(Country.IT)) { calculateFertilityRatesFromProjections(); calculatePopulationGrowthRatiosFromProjections(); - /////////////////////////////////////////////////POPULATE STATISTICS FOR VALIDATION///////////////////////////// - //Students by Age - validationStudentsByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_studentsByAge", 1, columnsValidationStudentsByAge); - - //Students by Region - validationStudentsByRegion = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_studentsByRegion", 1, columnsValidationStudentsByRegion); - - //Education level of over 17 year olds - validationEducationLevel = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_educationLevel", 1, columnsValidationEducationLevel); - - //Education level by age group - validationEducationLevelByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_educationLevelByAge", 1, columnsValidationEducationLevelByAge); - - //Education level by region - validationEducationLevelByRegion = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_educationLevelByRegion", 1, columnsValidationEducationLevelByRegion); - - //Partnered BU share by region - validationPartneredShareByRegion = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_partneredBUShareByRegion", 1, columnsValidationPartneredBUShareByRegion); - - //Disabled by age - validationDisabledByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_disabledByAgeGroup", 1, columnsValidationDisabledByAgeGroup); - - validationDisabledByGender = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_disabledByGender", 1, columnsValidationDisabledByGender); - - //Health by age - validationHealthByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_healthByAgeGroup", 1, columnsValidationHealthByAgeGroup); - - //Mental health by age and gender - validationMentalHealthByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_mentalHealthByAgeGroup", 1, columnsValidationMentalHealthByAgeGroup); - - //Psychological distress by age and gender - validationPsychDistressByAge = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_psychDistressByAgeGroup", 1, columnsValidationMentalHealthByAgeGroup); - validationPsychDistressByAgeLow = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_psychDistressByAgeGroupLowED", 1, columnsValidationMentalHealthByAgeGroup); - validationPsychDistressByAgeMed = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_psychDistressByAgeGroupMedED", 1, columnsValidationMentalHealthByAgeGroup); - validationPsychDistressByAgeHigh = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_psychDistressByAgeGroupHiEd", 1, columnsValidationMentalHealthByAgeGroup); - - //Employment by gender - validationEmploymentByGender = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_employmentByGender", 1, columnsValidationEmploymentByGender); - - //Employment by age and gender - validationEmploymentByAgeAndGender = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_employmentByGenderAndAge", 1, columnsValidationEmploymentByGenderAndAge); - - //Employment by maternity - validationEmploymentByMaternity = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_employmentByMaternity", 1, columnsValidationEmploymentByMaternity); - - //Employment by gender and region - validationEmploymentByGenderAndRegion = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_employmentByGenderAndRegion", 1, columnsValidationEmploymentByGenderAndRegion); - - //Labour supply by education - validationLabourSupplyByEducation = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_labourSupplyByEducation", 1, columnsValidationLabourSupplyByEducation); - - //Activity status - validationActivityStatus = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_activityStatus", 1, columnsValidationActivityStatus); - - //Homeownership status - validationHomeownershipBenefitUnits = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_homeownership", 1, columnsValidationHomeownership); - - //Gross earnings yearly by education and gender (for employed persons) - validationGrossEarningsByGenderAndEducation = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_grossEarningsByGenderAndEdu", 1, columnsValidationByGenderAndEducation); - - //Hourly wages by education and gender (for employed persons) - validationLhwByGenderAndEducation = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_lhwByGenderAndEdu", 1, 8); - - //Hours worked weekly by education and gender (for employed persons) - hourlyWageByGenderAndEducation = ExcelAssistant.loadCoefficientMap("input/validation_statistics.xlsx", countryString + "_hourlywageByGenderAndEdu", 1, columnsValidationByGenderAndEducation); } /** @@ -1735,6 +1330,7 @@ public static void updateUnemploymentRate(int year) { } */ + public static NormalDistribution getStandardNormalDistribution() { return standardNormalDistribution; } @@ -1898,126 +1494,58 @@ public static void setCountryBenefitUnitName() { public static MultiKeyCoefficientMap getStudentShareProjections() { return studentShareProjections; } - public static MultiLogitRegression getRegEducationLevel() { + public static MultinomialRegression getRegEducationLevel() { return regEducationLevel; } - public static MultiKeyCoefficientMap getEmploymentsFurloughedFull() { - return employmentsFurloughedFull; - } - - public static double getEmploymentsFurloughedFullForMonthYear(int month, int year) { - if (employmentsFurloughedFull.get(month, year) != null) { - return ((Number) employmentsFurloughedFull.get(month, year)).doubleValue(); - } else return 0.; - } - - public static void setEmploymentsFurloughedFull(MultiKeyCoefficientMap employmentsFurloughedFull) { - Parameters.employmentsFurloughedFull = employmentsFurloughedFull; - } - - public static MultiKeyCoefficientMap getEmploymentsFurloughedFlex() { - return employmentsFurloughedFlex; - } - - public static double getEmploymentsFurloughedFlexForMonthYear(int month, int year) { - if (employmentsFurloughedFlex.get(month, year) != null) { - return ((Number) employmentsFurloughedFlex.get(month, year)).doubleValue(); - } else return 0.; - } - - public static void setEmploymentsFurloughedFlex(MultiKeyCoefficientMap employmentsFurloughedFlex) { - Parameters.employmentsFurloughedFlex = employmentsFurloughedFlex; - } - - public static OrderedProbitRegression getRegHealthH1a() { - return regHealthH1a; - } - public static OrderedProbitRegression getRegHealthH1b() { - return regHealthH1b; - } - public static ProbitRegression getRegHealthH2b() { return regHealthH2b; } + public static GeneralisedOrderedRegression getRegHealthH1a() { return regHealthH1a; } + public static GeneralisedOrderedRegression getRegHealthH1b() { return regHealthH1b; } + public static BinomialRegression getRegHealthH2b() { return regHealthH2b; } - public static ProbitRegression getRegReceiveCareS1a() { return regReceiveCareS1a; } + public static BinomialRegression getRegReceiveCareS1a() { return regReceiveCareS1a; } public static LinearRegression getRegCareHoursS1b() { return regCareHoursS1b; } - public static ProbitRegression getRegNeedCareS2a() { return regNeedCareS2a; } - public static ProbitRegression getRegReceiveCareS2b() { return regReceiveCareS2b; } - public static MultiLogitRegression getRegSocialCareMarketS2c() { return regSocialCareMarketS2c; } - public static ProbitRegression getRegReceiveCarePartnerS2d() { return regReceiveCarePartnerS2d; } - public static MultiLogitRegression getRegPartnerSupplementaryCareS2e() { return regPartnerSupplementaryCareS2e; } - public static MultiLogitRegression getRegNotPartnerInformalCareS2f() { return regNotPartnerInformalCareS2f; } + public static BinomialRegression getRegNeedCareS2a() { return regNeedCareS2a; } + public static BinomialRegression getRegReceiveCareS2b() { return regReceiveCareS2b; } + public static MultinomialRegression getRegSocialCareMarketS2c() { return regSocialCareMarketS2c; } + public static BinomialRegression getRegReceiveCarePartnerS2d() { return regReceiveCarePartnerS2d; } + public static MultinomialRegression getRegPartnerSupplementaryCareS2e() { return regPartnerSupplementaryCareS2e; } + public static MultinomialRegression getRegNotPartnerInformalCareS2f() { return regNotPartnerInformalCareS2f; } public static LinearRegression getRegPartnerCareHoursS2g() { return regPartnerCareHoursS2g; } public static LinearRegression getRegDaughterCareHoursS2h() { return regDaughterCareHoursS2h; } public static LinearRegression getRegSonCareHoursS2i() { return regSonCareHoursS2i; } public static LinearRegression getRegOtherCareHoursS2j() { return regOtherCareHoursS2j; } public static LinearRegression getRegFormalCareHoursS2k() { return regFormalCareHoursS2k; } - public static ProbitRegression getRegCarePartnerProvCareToOtherS3a() { return regCarePartnerProvCareToOtherS3a; } - public static ProbitRegression getRegNoCarePartnerProvCareToOtherS3b() { return regNoCarePartnerProvCareToOtherS3b; } - public static ProbitRegression getRegNoPartnerProvCareToOtherS3c() { return regNoPartnerProvCareToOtherS3c; } - public static MultiLogitRegression getRegInformalCareToS3d() { return regInformalCareToS3d; } + public static BinomialRegression getRegCarePartnerProvCareToOtherS3a() { return regCarePartnerProvCareToOtherS3a; } + public static BinomialRegression getRegNoCarePartnerProvCareToOtherS3b() { return regNoCarePartnerProvCareToOtherS3b; } + public static BinomialRegression getRegNoPartnerProvCareToOtherS3c() { return regNoPartnerProvCareToOtherS3c; } + public static MultinomialRegression getRegInformalCareToS3d() { return regInformalCareToS3d; } public static LinearRegression getRegCareHoursProvS3e() { return regCareHoursProvS3e; } - public static ProbitRegression getRegUnemploymentMaleGraduateU1a() { return regUnemploymentMaleGraduateU1a; } - public static ProbitRegression getRegUnemploymentMaleNonGraduateU1b() { return regUnemploymentMaleNonGraduateU1b; } - public static ProbitRegression getRegUnemploymentFemaleGraduateU1c() { return regUnemploymentFemaleGraduateU1c; } - public static ProbitRegression getRegUnemploymentFemaleNonGraduateU1d() { return regUnemploymentFemaleNonGraduateU1d; } + public static BinomialRegression getRegUnemploymentMaleGraduateU1a() { return regUnemploymentMaleGraduateU1a; } + public static BinomialRegression getRegUnemploymentMaleNonGraduateU1b() { return regUnemploymentMaleNonGraduateU1b; } + public static BinomialRegression getRegUnemploymentFemaleGraduateU1c() { return regUnemploymentFemaleGraduateU1c; } + public static BinomialRegression getRegUnemploymentFemaleNonGraduateU1d() { return regUnemploymentFemaleNonGraduateU1d; } public static LinearRegression getRegHealthHM1Level() { return regHealthHM1Level; } public static LinearRegression getRegHealthHM2LevelMales() { return regHealthHM2LevelMales; } public static LinearRegression getRegHealthHM2LevelFemales() { return regHealthHM2LevelFemales; } - public static LogitRegression getRegHealthHM1Case() { - return regHealthHM1Case; - } - public static LogitRegression getRegHealthHM2CaseMales() { - return regHealthHM2CaseMales; - } - public static LogitRegression getRegHealthHM2CaseFemales() { - return regHealthHM2CaseFemales; - } - - public static ProbitRegression getRegEducationE1a() { - return regEducationE1a; - } - - public static ProbitRegression getRegEducationE1b() { - return regEducationE1b; - } + public static BinomialRegression getRegHealthHM1Case() {return regHealthHM1Case;} + public static BinomialRegression getRegHealthHM2CaseMales() {return regHealthHM2CaseMales;} + public static BinomialRegression getRegHealthHM2CaseFemales() {return regHealthHM2CaseFemales;} - public static OrderedProbitRegression getRegEducationE2a() { - return regEducationE2a; - } - - public static ProbitRegression getRegPartnershipU1a() { - return regPartnershipU1a; - } + public static BinomialRegression getRegEducationE1a() {return regEducationE1a;} + public static BinomialRegression getRegEducationE1b() {return regEducationE1b;} + public static GeneralisedOrderedRegression getRegEducationE2a() {return regEducationE2a;} - public static ProbitRegression getRegPartnershipU1b() { - return regPartnershipU1b; - } - - public static ProbitRegression getRegPartnershipU2b() { - return regPartnershipU2b; - } - - public static ProbitRegression getRegPartnershipITU1() { - return regPartnershipITU1; - } - - public static ProbitRegression getRegPartnershipITU2() { - return regPartnershipITU2; - } - - public static ProbitRegression getRegFertilityF1a() { - return regFertilityF1a; - } - - public static ProbitRegression getRegFertilityF1b() { - return regFertilityF1b; - } + public static BinomialRegression getRegPartnershipU1a() {return regPartnershipU1a;} + public static BinomialRegression getRegPartnershipU1b() {return regPartnershipU1b;} + public static BinomialRegression getRegPartnershipU2b() {return regPartnershipU2b;} + public static BinomialRegression getRegPartnershipITU1() {return regPartnershipITU1;} + public static BinomialRegression getRegPartnershipITU2() {return regPartnershipITU2;} - public static ProbitRegression getRegFertilityF1() { - return regFertilityF1; - } + public static BinomialRegression getRegFertilityF1a() {return regFertilityF1a;} + public static BinomialRegression getRegFertilityF1b() {return regFertilityF1b;} + public static BinomialRegression getRegFertilityF1() {return regFertilityF1;} public static LinearRegression getRegIncomeI1a() { return regIncomeI1a; @@ -2045,15 +1573,12 @@ public static LinearRegression getRegIncomeI5b_amount() { public static LinearRegression getRegIncomeI6b_amount() { return regIncomeI6b_amount; } - public static LogitRegression getRegIncomeI3a_selection() { return regIncomeI3a_selection; } - - public static LogitRegression getRegIncomeI3b_selection() { return regIncomeI3b_selection; } - public static LogitRegression getRegIncomeI5a_selection() { return regIncomeI5a_selection; } - public static LogitRegression getRegIncomeI6a_selection() { return regIncomeI6a_selection; } + public static BinomialRegression getRegIncomeI3a_selection() { return regIncomeI3a_selection; } + public static BinomialRegression getRegIncomeI3b_selection() { return regIncomeI3b_selection; } + public static BinomialRegression getRegIncomeI5a_selection() { return regIncomeI5a_selection; } + public static BinomialRegression getRegIncomeI6a_selection() { return regIncomeI6a_selection; } - public static ProbitRegression getRegHomeownershipHO1a() { - return regHomeownershipHO1a; - } + public static BinomialRegression getRegHomeownershipHO1a() {return regHomeownershipHO1a;} public static Set getCountryRegions() { return countryRegions; @@ -2066,7 +1591,8 @@ public static MultiKeyMap getFertilityRateByRegionYear() { public static double getFertilityRateByRegionYear(Region region, int year) { int yearHere = Math.max(fertilityProjectionsMinYear, Math.min(fertilityProjectionsMaxYear, year)); //We calculate the rate per woman, but the standard to report (and what is used in the estimates) is per 1000 hence multiplication - return 1000*((Number)fertilityRateByRegionYear.get(region, yearHere)).doubleValue(); + // return 1000*((Number)fertilityRateByRegionYear.get(region, yearHere)).doubleValue(); + return ((Number)fertilityRateByRegionYear.get(region, yearHere)).doubleValue(); } public static double getUnemploymentRateByGenderEducationAgeYear(Gender gender, Education education, int age, int year) { @@ -2194,10 +1720,6 @@ public static double getUnemploymentRatesForRegion(Region region) { } */ - public static MultiKeyCoefficientMap getMarriageTypesFrequency() { - return marriageTypesFrequency; - } - public static MultiKeyCoefficientMap getCoeffCovarianceHealthH1a() { return coeffCovarianceHealthH1a; } public static MultiKeyCoefficientMap getCoeffCovarianceHealthH1b() { return coeffCovarianceHealthH1b; } @@ -2251,19 +1773,19 @@ public synchronized static double[] getWageAndAgeDifferentialMultivariateNormalD return wageAndAgeDifferentialMultivariateNormalDistribution.sample(); } - public static ProbitRegression getRegLeaveHomeP1a() { + public static BinomialRegression getRegLeaveHomeP1a() { return regLeaveHomeP1a; } - public static ProbitRegression getRegRetirementR1a() { + public static BinomialRegression getRegRetirementR1a() { return regRetirementR1a; } - public static ProbitRegression getRegRetirementR1b() { + public static BinomialRegression getRegRetirementR1b() { return regRetirementR1b; } - public static ProbitRegression getRegChildcareC1a() { return regChildcareC1a; } + public static BinomialRegression getRegChildcareC1a() { return regChildcareC1a; } public static LinearRegression getRegChildcareC1b() { return regChildcareC1b; @@ -2367,29 +1889,15 @@ public static MultiKeyCoefficientMap getHourlyWageByGenderAndEducation() { } ///////////////////////////////////////////GETTERS FOR COVID-19 LABOUR TRANSITIONS////////////////////////////////// - public static ProbitRegression getRegC19LS_SE() { + public static BinomialRegression getRegC19LS_SE() { return regC19LS_SE; } - public static MultiLogitRegression getRegC19LS_E1() { - return regC19LS_E1; - } - - public static MultiLogitRegression getRegC19LS_FF1() { - return regC19LS_FF1; - } - - public static MultiLogitRegression getRegC19LS_FX1() { - return regC19LS_FX1; - } - - public static MultiLogitRegression getRegC19LS_S1() { - return regC19LS_S1; - } - - public static MultiLogitRegression getRegC19LS_U1() { - return regC19LS_U1; - } + public static MultinomialRegression getRegC19LS_E1() {return regC19LS_E1;} + public static MultinomialRegression getRegC19LS_FF1() {return regC19LS_FF1;} + public static MultinomialRegression getRegC19LS_FX1() {return regC19LS_FX1;} + public static MultinomialRegression getRegC19LS_S1() {return regC19LS_S1;} + public static MultinomialRegression getRegC19LS_U1() {return regC19LS_U1;} public static LinearRegression getRegC19LS_E2a() { return regC19LS_E2a; @@ -2419,7 +1927,7 @@ public static LinearRegression getRegC19LS_U2a() { return regC19LS_U2a; } - public static LogitRegression getRegC19LS_S3() { + public static BinomialRegression getRegC19LS_S3() { return regC19LS_S3; } @@ -2457,24 +1965,30 @@ public static LinearRegression getRegEmploymentSelectionFemaleNE() { public static void loadTimeSeriesFactorMaps(Country country) { + + // load time varying rates - priceMapRealSavingReturns = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_saving_returns", 1, 1); - priceMapRealDebtCostLow = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_debt_cost_low", 1, 1); - priceMapRealDebtCostHigh = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_debt_cost_hi", 1, 1); + // priceMapRealSavingReturns = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_saving_returns", 1, 1); + // priceMapRealDebtCostLow = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_debt_cost_low", 1, 1); + // priceMapRealDebtCostHigh = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_debt_cost_hi", 1, 1); // load time varying wage rates - wageRateFormalSocialCare = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_carer_hourly_wage", 1, 1); + // wageRateFormalSocialCare = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_carer_hourly_wage", 1, 1); // load time varying indices upratingIndexMapRealGDP = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_gdp", 1, 1); upratingIndexMapInflation = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_inflation", 1, 1); upratingIndexMapRealWageGrowth = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_wage_growth", 1, 1); - socialCareProvisionTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_care_adjustment", 1, 1); + // socialCareProvisionTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_care_adjustment", 1, 1); partnershipTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_cohabitation_adjustment", 1, 1); + retirementTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_retirement_adjustment", 1, 1); + disabilityTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_disability_adjustment", 1, 1); + studentsTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_students_adjustment", 1, 1); fertilityTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_fertility_adjustment", 1, 1); utilityTimeAdjustmentSingleMales = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_utility_adj_smales", 1, 1); utilityTimeAdjustmentSingleFemales = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_utility_adj_sfemales", 1, 1); utilityTimeAdjustmentCouples = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_utility_adj_couples", 1, 1); + utilityTimeAdjustment = ExcelAssistant.loadCoefficientMap("input/time_series_factor.xlsx", country.toString() + "_utility_adj_all", 1, 1); // rebase indices to base year defined by BASE_PRICE_YEAR rebaseIndexMap(TimeSeriesVariable.GDP); @@ -2484,6 +1998,9 @@ public static void loadTimeSeriesFactorMaps(Country country) { // load year-specific fiscal policy parameters socialCarePolicy = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "social care", 1, 8); partneredShare = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "partnership", 1, 1); + retiredShare = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "retirement", 1, 1); + disabledShare = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "disability", 1, 1); + studentShare = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "students", 1, 1); employedShareSingleMales = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "employment_smales", 1, 1); employedShareSingleFemales = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "employment_sfemales", 1, 1); employedShareCouples = ExcelAssistant.loadCoefficientMap("input/policy parameters.xlsx", "employment_couples", 1, 1); @@ -2492,10 +2009,16 @@ public static void loadTimeSeriesFactorMaps(Country country) { public static void instantiateAlignmentMaps() { partnershipAlignAdjustment = new HashMap<>(); + retirementAlignAdjustment = new HashMap<>(); + disabilityAlignAdjustment = new HashMap<>(); + studentsAlignAdjustment = new HashMap<>(); fertilityAlignAdjustment = new HashMap<>(); for (int yy=startYear; yy<=endYear; yy++) { partnershipAlignAdjustment.put(yy,0.0); fertilityAlignAdjustment.put(yy,0.0); + retirementAlignAdjustment.put(yy,0.0); + disabilityAlignAdjustment.put(yy,0.0); + studentsAlignAdjustment.put(yy,0.0); } } @@ -2562,6 +2085,9 @@ private static MultiKeyCoefficientMap getTimeSeriesValueMap(TimeSeriesVariable t case FertilityAdjustment -> { map = fertilityTimeAdjustment; } + case UtilityAdjustment -> { + map = utilityTimeAdjustment; + } case UtilityAdjustmentSingleMales -> { map = utilityTimeAdjustmentSingleMales; } @@ -2571,15 +2097,21 @@ private static MultiKeyCoefficientMap getTimeSeriesValueMap(TimeSeriesVariable t case UtilityAdjustmentCouples -> { map = utilityTimeAdjustmentCouples; } + case RetirementAdjustment -> { + map = retirementTimeAdjustment; + } + case DisabilityAdjustment -> { + map = disabilityTimeAdjustment; + } + case InSchoolAdjustment -> { + map = studentsTimeAdjustment; + } case HighEducationRate -> { map = projectionsHighEdu; } case LowEducationRate -> { map = projectionsLowEdu; } - case EmploymentAlignment -> { - map = employmentAlignment; - } case FixedRetirementAge -> { map = fixedRetireAge; } @@ -2594,6 +2126,15 @@ private static MultiKeyCoefficientMap getTargetShareMap(TargetShares targetShare case Partnership -> { map = partneredShare; } + case Retirement -> { + map = retiredShare; + } + case Disability -> { + map = disabledShare; + } + case Students -> { + map = studentShare; + } case EmploymentSingleMales -> { map = employedShareSingleMales; } @@ -2603,6 +2144,9 @@ private static MultiKeyCoefficientMap getTargetShareMap(TargetShares targetShare case EmploymentCouples -> { map = employedShareCouples; } + case Employment -> { + map = employedShare; + } } return map; @@ -3134,6 +2678,23 @@ public static MultiKeyCoefficientMap getCoeffLabourSupplyUtilityMales() { return coeffLabourSupplyUtilityMales; } + public static MultiKeyCoefficientMap getCoeffLabourSupplyUtilityMalesWithDependent() { + return coeffLabourSupplyUtilityMalesWithDependent; + } + + public static MultiKeyCoefficientMap getCoeffLabourSupplyUtilityFemalesWithDependent() { + return coeffLabourSupplyUtilityFemalesWithDependent; + } + + public static MultiKeyCoefficientMap getCoeffLabourSupplyUtilityACMales() { + return coeffLabourSupplyUtilityACMales; + } + + public static MultiKeyCoefficientMap getCoeffLabourSupplyUtilityACFemales() { + return coeffLabourSupplyUtilityACFemales; + } + + public static void setCoeffLabourSupplyUtilityMales(MultiKeyCoefficientMap coeffLabourSupplyUtilityMales) { Parameters.coeffLabourSupplyUtilityMales = coeffLabourSupplyUtilityMales; } @@ -3218,6 +2779,18 @@ public static double getAlignmentValue(int year, AlignmentVariable variableType) throw new RuntimeException("value undefined for fertilityAlignAdjustment in year " + year); return val; } + case RetirementAlignment -> { + Double val = retirementAlignAdjustment.get(year); + if (val==null) + throw new RuntimeException("value undefined for retirementAlignAdjustment in year " + year); + return val; + } + case DisabilityAlignment -> { + Double val = disabilityAlignAdjustment.get(year); + if (val==null) + throw new RuntimeException("value undefined for disabilityAlignAdjustment in year " + year); + return val; + } default -> { throw new RuntimeException("failed to identify alignment value type to get"); } @@ -3232,6 +2805,12 @@ public static void setAlignmentValue(int year, double val, AlignmentVariable var case FertilityAlignment -> { fertilityAlignAdjustment.put(year, val); } + case RetirementAlignment -> { + retirementAlignAdjustment.put(year, val); + } + case DisabilityAlignment -> { + disabilityAlignAdjustment.put(year, val); + } default -> { throw new RuntimeException("failed to identify alignment value type in set"); } @@ -3245,6 +2824,13 @@ public static double getFertilityRateByYear(int year) { return val; } + public static double getRetiredShareByYear(int year) { + Double val = retiredShareByYear.get(year); + if (val==null) + throw new RuntimeException("value undefined for getRetiredShareByYear in year " + year); + return val; + } + public static void databaseSetup(Country country, boolean executeWithGui, int startYear) { // remove database file if it exists diff --git a/src/main/java/simpaths/data/RegressionName.java b/src/main/java/simpaths/data/RegressionName.java index 8b7d4b260..1a2f92fbb 100644 --- a/src/main/java/simpaths/data/RegressionName.java +++ b/src/main/java/simpaths/data/RegressionName.java @@ -1,37 +1,66 @@ package simpaths.data; +import microsim.statistics.regression.RegressionType; + public enum RegressionName { - EducationE1a(RegressionType.StandardProbit), - EducationE1b(RegressionType.StandardProbit), + ChildcareC1b(RegressionType.Linear), + + EducationE1a(RegressionType.Probit), + EducationE1b(RegressionType.Probit), EducationE2a(RegressionType.OrderedProbit), - HealthH1a(RegressionType.OrderedProbit), - HealthH1b(RegressionType.OrderedProbit), - HealthH2b(RegressionType.StandardProbit), - SocialCareS2a(RegressionType.StandardProbit), - SocialCareS2b(RegressionType.StandardProbit), + + FertilityF1a(RegressionType.Probit), + FertilityF1b(RegressionType.Probit), + + PartnershipU1a(RegressionType.Probit), + PartnershipU1b(RegressionType.Probit), + PartnershipU2b(RegressionType.Probit), + + HealthH1a(RegressionType.GenOrderedLogit), + HealthH1b(RegressionType.GenOrderedLogit), + HealthH2b(RegressionType.Probit), + + HealthHM1Level(RegressionType.Linear), + HealthHM2LevelMales(RegressionType.Linear), + HealthHM2LevelFemales(RegressionType.Linear), + HealthHM1Case(RegressionType.Logit), + HealthHM2CaseMales(RegressionType.Logit), + HealthHM2CaseFemales(RegressionType.Logit), + + RMSE(RegressionType.Linear), + + SocialCareS1a(RegressionType.Probit), + SocialCareS1b(RegressionType.Linear), + SocialCareS2a(RegressionType.Probit), + SocialCareS2b(RegressionType.Probit), SocialCareS2c(RegressionType.MultinomialLogit), - SocialCareS3c(RegressionType.StandardProbit), + SocialCareS2d(RegressionType.Probit), + SocialCareS2e(RegressionType.MultinomialLogit), + SocialCareS2f(RegressionType.MultinomialLogit), + SocialCareS2g(RegressionType.Linear), + SocialCareS2h(RegressionType.Linear), + SocialCareS2i(RegressionType.Linear), + SocialCareS2j(RegressionType.Linear), + SocialCareS2k(RegressionType.Linear), + SocialCareS3a(RegressionType.Probit), + SocialCareS3b(RegressionType.Probit), + SocialCareS3c(RegressionType.Probit), SocialCareS3d(RegressionType.MultinomialLogit), SocialCareS3e(RegressionType.Linear), - PartnershipU1a(RegressionType.AdjustedStandardProbit), - PartnershipU1b(RegressionType.AdjustedStandardProbit), - PartnershipU2b(RegressionType.ReversedProbit), - FertilityF1a(RegressionType.AdjustedStandardProbit), - FertilityF1b(RegressionType.AdjustedStandardProbit), + + UnemploymentU1a(RegressionType.Probit), + UnemploymentU1b(RegressionType.Probit), + UnemploymentU1c(RegressionType.Probit), + UnemploymentU1d(RegressionType.Probit), + WagesMales(RegressionType.Linear), WagesMalesE(RegressionType.Linear), WagesMalesNE(RegressionType.Linear), WagesFemales(RegressionType.Linear), WagesFemalesE(RegressionType.Linear), - WagesFemalesNE(RegressionType.Linear), - UnemploymentU1a(RegressionType.ReversedProbit), - UnemploymentU1b(RegressionType.ReversedProbit), - UnemploymentU1c(RegressionType.ReversedProbit), - UnemploymentU1d(RegressionType.ReversedProbit), - ChildcareC1b(RegressionType.Linear), - RMSE(RegressionType.RMSE); + WagesFemalesNE(RegressionType.Linear); private final RegressionType type; diff --git a/src/main/java/simpaths/data/startingpop/DataParser.java b/src/main/java/simpaths/data/startingpop/DataParser.java index df82ac94a..8ed2f481a 100644 --- a/src/main/java/simpaths/data/startingpop/DataParser.java +++ b/src/main/java/simpaths/data/startingpop/DataParser.java @@ -152,7 +152,7 @@ private static void parse(String inputFileLocation, String inputFileName, Connec //Labour Market Economic Status + "ALTER TABLE " + personTable + " ADD activity_status VARCHAR_IGNORECASE;" - + "UPDATE " + personTable + " SET les_c4 = 3 WHERE les_c4 = 1 AND CAST(potential_earnings_hourly AS FLOAT)<0.01;" + + "UPDATE " + personTable + " SET les_c4 = 3 WHERE les_c4 = 1 AND CAST(obs_earnings_hourly AS FLOAT)<0.01;" + "UPDATE " + personTable + " SET activity_status = 'EmployedOrSelfEmployed' WHERE les_c4 = 1;" + "UPDATE " + personTable + " SET activity_status = 'Student' WHERE les_c4 = 2;" + "UPDATE " + personTable + " SET activity_status = 'NotEmployed' WHERE les_c4 = 3;" @@ -160,6 +160,16 @@ private static void parse(String inputFileLocation, String inputFileName, Connec + "ALTER TABLE " + personTable + " DROP COLUMN les_c4;" + "ALTER TABLE " + personTable + " ALTER COLUMN activity_status RENAME TO les_c4;" + //Lag(1) of les_c4 + + "ALTER TABLE " + personTable + " ADD activity_status VARCHAR_IGNORECASE;" + + "UPDATE " + personTable + " SET l1_les_c4 = 3 WHERE l1_les_c4 = 1 AND CAST(l1_obs_earnings_hourly AS FLOAT)<0.01;" + + "UPDATE " + personTable + " SET activity_status = 'EmployedOrSelfEmployed' WHERE l1_les_c4 = 1;" + + "UPDATE " + personTable + " SET activity_status = 'Student' WHERE l1_les_c4 = 2;" + + "UPDATE " + personTable + " SET activity_status = 'NotEmployed' WHERE l1_les_c4 = 3;" + + "UPDATE " + personTable + " SET activity_status = 'Retired' WHERE l1_les_c4 = 4;" + + "ALTER TABLE " + personTable + " DROP COLUMN l1_les_c4;" + + "ALTER TABLE " + personTable + " ALTER COLUMN activity_status RENAME TO les_c4_lag1;" + //DEMOGRAPHIC: Long-term sick or disabled (to be used with Indicator enum when defined in Person class) + "ALTER TABLE " + personTable + " ADD sick_longterm VARCHAR_IGNORECASE;" + "UPDATE " + personTable + " SET sick_longterm = 'False' WHERE dlltsd = 0;" @@ -167,13 +177,6 @@ private static void parse(String inputFileLocation, String inputFileName, Connec + "ALTER TABLE " + personTable + " DROP COLUMN dlltsd;" + "ALTER TABLE " + personTable + " ALTER COLUMN sick_longterm RENAME TO dlltsd;" - //DEMOGRAPHIC: Need social care (to be used with Indicator enum when defined in Person class) - + "ALTER TABLE " + personTable + " ADD need_care VARCHAR_IGNORECASE;" - + "UPDATE " + personTable + " SET need_care = 'False' WHERE need_socare = 0;" - + "UPDATE " + personTable + " SET need_care = 'True' WHERE need_socare = 1;" - + "ALTER TABLE " + personTable + " DROP COLUMN need_socare;" - + "ALTER TABLE " + personTable + " ALTER COLUMN need_care RENAME TO need_socare;" - //SYSTEM: Year left education (to be used with Indicator enum when defined in Person class) + "ALTER TABLE " + personTable + " ADD education_left VARCHAR_IGNORECASE;" + "UPDATE " + personTable + " SET education_left = 'False' WHERE sedex = 0;" @@ -195,15 +198,6 @@ private static void parse(String inputFileLocation, String inputFileName, Connec + "ALTER TABLE " + personTable + " DROP COLUMN dhh_owned;" + "ALTER TABLE " + personTable + " ALTER COLUMN dhh_owned_add RENAME TO dhh_owned;" - //Social care - + "ALTER TABLE " + personTable + " ADD socare_provided_to VARCHAR_IGNORECASE;" - + "UPDATE " + personTable + " SET socare_provided_to = 'None' WHERE careWho = 0;" - + "UPDATE " + personTable + " SET socare_provided_to = 'OnlyPartner' WHERE careWho = 1;" - + "UPDATE " + personTable + " SET socare_provided_to = 'PartnerAndOther' WHERE careWho = 2;" - + "UPDATE " + personTable + " SET socare_provided_to = 'OnlyOther' WHERE careWho = 3;" - + "ALTER TABLE " + personTable + " DROP COLUMN careWho;" - + "ALTER TABLE " + personTable + " ALTER COLUMN aidhrs RENAME TO socare_provided_hrs;" - //SYSTEM : Year + "ALTER TABLE " + personTable + " ALTER COLUMN stm RENAME TO system_year;" @@ -212,8 +206,11 @@ private static void parse(String inputFileLocation, String inputFileName, Connec + "ALTER TABLE " + personTable + " ALTER COLUMN lhw RENAME TO " + Parameters.HOURS_WORKED_WEEKLY + ";" + "ALTER TABLE " + personTable + " ADD work_sector VARCHAR_IGNORECASE DEFAULT 'Private_Employee';" //Here we assume by default that people are employed - this is because the MultiKeyMaps holding households have work_sector as a key, and cannot handle null values for work_sector. TODO: Need to check that this assumption is OK. + + "ALTER TABLE " + personTable + " ALTER COLUMN idmother BIGINT;" + "UPDATE " + personTable + " SET idmother = null WHERE idmother = -9;" + + "ALTER TABLE " + personTable + " ALTER COLUMN idfather BIGINT;" + "UPDATE " + personTable + " SET idfather = null WHERE idfather = -9;" + + "UPDATE " + personTable + " SET liwwh = null WHERE liwwh = -9;" //Rename idbenefitunit to BU_ID + "ALTER TABLE " + personTable + " ALTER COLUMN idbenefitunit RENAME TO buid;" @@ -275,11 +272,6 @@ private static void parse(String inputFileLocation, String inputFileName, Connec + "ALTER TABLE " + benefitUnitTable + " DROP COLUMN dhh_owned;" + "ALTER TABLE " + benefitUnitTable + " ALTER COLUMN dhh_owned_add RENAME TO dhh_owned;" - //WEALTH - + "UPDATE " + benefitUnitTable + " SET liquid_wealth = 0.0 WHERE liquid_wealth = -9.0;" - + "UPDATE " + benefitUnitTable + " SET tot_pen = 0.0 WHERE tot_pen = -9.0;" - + "UPDATE " + benefitUnitTable + " SET nvmhome = 0.0 WHERE nvmhome = -9.0;" - //Add panel entity key + "ALTER TABLE " + benefitUnitTable + " ALTER COLUMN idbenefitunit RENAME TO id;" + "ALTER TABLE " + benefitUnitTable + " ADD COLUMN simulation_time INT DEFAULT " + startyear + ";" diff --git a/src/main/java/simpaths/data/statistics/Statistics3.java b/src/main/java/simpaths/data/statistics/Statistics3.java index 408c53a58..0c0ebd9ab 100644 --- a/src/main/java/simpaths/data/statistics/Statistics3.java +++ b/src/main/java/simpaths/data/statistics/Statistics3.java @@ -151,7 +151,6 @@ public void update(SimPathsModel model) { setFertilityRateSimulated(val); setFertilityRateTarget(Parameters.getFertilityRateByYear(model.getYear()-1)); - setSocialCareAdjustmentFactor(Parameters.getTimeSeriesValue(model.getYear()-1, TimeSeriesVariable.CareProvisionAdjustment)); setUtilityAdjustmentFactorSmales(Parameters.getTimeSeriesValue(model.getYear()-1, TimeSeriesVariable.UtilityAdjustmentSingleMales)); setUtilityAdjustmentFactorSfemales(Parameters.getTimeSeriesValue(model.getYear()-1, TimeSeriesVariable.UtilityAdjustmentSingleFemales)); setUtilityAdjustmentFactorCouples(Parameters.getTimeSeriesValue(model.getYear()-1, TimeSeriesVariable.UtilityAdjustmentCouples)); diff --git a/src/main/java/simpaths/experiment/SimPathsMultiRun.java b/src/main/java/simpaths/experiment/SimPathsMultiRun.java index 4332884b2..70f9fb1c5 100644 --- a/src/main/java/simpaths/experiment/SimPathsMultiRun.java +++ b/src/main/java/simpaths/experiment/SimPathsMultiRun.java @@ -68,7 +68,7 @@ public static void main(String[] args) { if (lastDatabaseCountryAndYear.keySet().stream().anyMatch(key -> key.toString().equals("MultiKey[IT]"))) { countryString = "Italy"; } else { - countryString = "United Kingdom"; + countryString = "Italy"; } country = Country.getCountryFromNameString(countryString); String valueYear = lastDatabaseCountryAndYear.getValue(country.toString()).toString(); diff --git a/src/main/java/simpaths/experiment/SimPathsObserver.java b/src/main/java/simpaths/experiment/SimPathsObserver.java index e9fc8757d..b7f094b1f 100644 --- a/src/main/java/simpaths/experiment/SimPathsObserver.java +++ b/src/main/java/simpaths/experiment/SimPathsObserver.java @@ -2,27 +2,7 @@ package simpaths.experiment; // import Java packages -import java.awt.*; -import java.util.*; -import javax.swing.JComponent; -import javax.swing.JInternalFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.ScrollPaneConstants; - -// import plug-in packages -import simpaths.data.filters.*; -import simpaths.model.BenefitUnit; -import simpaths.model.SimPathsModel; -import simpaths.model.Validator; -import simpaths.model.enums.*; -import org.apache.commons.collections4.map.LinkedMap; -import org.apache.commons.collections4.map.MultiKeyMap; -import org.apache.log4j.Logger; -import net.miginfocom.swing.MigLayout; -// import JAS-mine packages import microsim.annotation.GUIparameter; import microsim.engine.AbstractSimulationObserverManager; import microsim.engine.SimulationCollectorManager; @@ -32,22 +12,32 @@ import microsim.event.EventListener; import microsim.event.SingleTargetEvent; import microsim.gui.GuiUtils; -import microsim.gui.plot.IndividualBarSimulationPlotter; -import microsim.gui.plot.ScatterplotSimulationPlotterRefreshable; -import microsim.gui.plot.Weighted_PyramidPlotter; -import microsim.gui.plot.TimeSeriesSimulationPlotter; -import microsim.gui.plot.Weighted_HistogramSimulationPlotter; +import microsim.gui.plot.*; import microsim.statistics.IDoubleSource; import microsim.statistics.ILongSource; import microsim.statistics.functions.MultiTraceFunction; import microsim.statistics.weighted.Weighted_CrossSection; import microsim.statistics.weighted.functions.Weighted_MeanArrayFunction; import microsim.statistics.weighted.functions.Weighted_SumArrayFunction; - -// import LABOURsim packages -import simpaths.model.Person; -import simpaths.data.Parameters; +import net.miginfocom.swing.MigLayout; +import org.apache.commons.collections4.map.LinkedMap; +import org.apache.commons.collections4.map.MultiKeyMap; +import org.apache.log4j.Logger; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; +import simpaths.data.Parameters; +import simpaths.data.filters.*; +import simpaths.model.BenefitUnit; +import simpaths.model.Person; +import simpaths.model.SimPathsModel; +import simpaths.model.Validator; +import simpaths.model.enums.Education; +import simpaths.model.enums.Gender; +import simpaths.model.enums.HistogramTypeEnum; +import simpaths.model.enums.Region; + +import javax.swing.*; +import java.awt.*; +import java.util.*; /** @@ -67,7 +57,7 @@ public class SimPathsObserver extends AbstractSimulationObserverManager implemen private Boolean showAdditionalCharts = true; @GUIparameter(description = "Enable validation statistics") - private Boolean showValidationStatistics = true; + private Boolean showValidationStatistics = false; @GUIparameter(description = "Set the time-period between chart updates") private Double displayFrequency = 1.; @@ -219,7 +209,9 @@ public void buildObjects() { model = (SimPathsModel) getManager(); final SimPathsCollector collector = (SimPathsCollector) getCollectorManager(); - validator = new Validator(); + if (showValidationStatistics) { + validator = new Validator(); + } //Renderers - these allow different graphs to use different look for the series displayed XYLineAndShapeRenderer studentAgeRenderer = new XYLineAndShapeRenderer(); //Set up a new renderer to define series colors for this chart @@ -242,6 +234,8 @@ public void buildObjects() { AgeGroupCSfilter age40_59Filter = new AgeGroupCSfilter(40, 59); AgeGroupCSfilter age60_79Filter = new AgeGroupCSfilter(60, 79); AgeGroupCSfilter age80_100Filter = new AgeGroupCSfilter(80, 100); + AgeGroupCSfilter age18_65Filter = new AgeGroupCSfilter(18, 65); + AgeGroupCSfilter age66_81Filter = new AgeGroupCSfilter(66, 81); AgeGroupCSfilter age10_19Filter = new AgeGroupCSfilter(10, 19); AgeGroupCSfilter age20_29Filter = new AgeGroupCSfilter(20,29); @@ -539,19 +533,28 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer notEmployedCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isNotEmployed); Weighted_CrossSection.Integer studentCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isStudent); Weighted_CrossSection.Integer retiredCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isRetired); + Weighted_CrossSection.Integer retired1865CS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isRetired); + Weighted_CrossSection.Integer retired6681CS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isRetired); Weighted_CrossSection.Integer notEmployedRetiredCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.IntegerVariables.isNotEmployedOrRetired); + retired1865CS.setFilter(age18_65Filter); + retired6681CS.setFilter(age66_81Filter); + TimeSeriesSimulationPlotter activityStatusPlotter = new TimeSeriesSimulationPlotter("Share of individuals by activity status", ""); activityStatusPlotter.addSeries("Employed", new Weighted_MeanArrayFunction(employedCS), null, colorArrayList.get(0), false); activityStatusPlotter.addSeries("Not Employed / Retired", new Weighted_MeanArrayFunction(notEmployedRetiredCS), null, colorArrayList.get(1), false); activityStatusPlotter.addSeries("Not Employed", new Weighted_MeanArrayFunction(notEmployedCS), null, colorArrayList.get(4), false); activityStatusPlotter.addSeries("Student", new Weighted_MeanArrayFunction(studentCS), null, colorArrayList.get(2), false); activityStatusPlotter.addSeries("Retired", new Weighted_MeanArrayFunction(retiredCS), null, colorArrayList.get(3), false); + activityStatusPlotter.addSeries("Retired 18_65", new Weighted_MeanArrayFunction(retired1865CS), null, colorArrayList.get(5), false); + activityStatusPlotter.addSeries("Retired 66_81", new Weighted_MeanArrayFunction(retired6681CS), null, colorArrayList.get(6), false); - activityStatusPlotter.addSeries("Employed validation", validator, Validator.DoublesVariables.activityStatus_Employed, colorArrayList.get(0), true); - activityStatusPlotter.addSeries("Not Employed / Retired validation", validator, Validator.DoublesVariables.activityStatus_NotEmployedRetired, colorArrayList.get(1), true); - activityStatusPlotter.addSeries("Student validation", validator, Validator.DoublesVariables.activityStatus_Student, colorArrayList.get(2), true); - // activityStatusPlotter.addSeries("Retired validation", validator, Validator.DoublesVariables.activityStatus_Retired, colorArrayList.get(3), true); + if (showValidationStatistics) { + activityStatusPlotter.addSeries("Employed validation", validator, Validator.DoublesVariables.activityStatus_Employed, colorArrayList.get(0), true); + activityStatusPlotter.addSeries("Not Employed / Retired validation", validator, Validator.DoublesVariables.activityStatus_NotEmployedRetired, colorArrayList.get(1), true); + activityStatusPlotter.addSeries("Student validation", validator, Validator.DoublesVariables.activityStatus_Student, colorArrayList.get(2), true); + // activityStatusPlotter.addSeries("Retired validation", validator, Validator.DoublesVariables.activityStatus_Retired, colorArrayList.get(3), true); + } activityStatusPlotter.setName("Activity status"); updateChartSet.add(activityStatusPlotter); @@ -563,7 +566,9 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Double homeownersBUsCS = new Weighted_CrossSection.Double(model.getBenefitUnits(), BenefitUnit.Regressors.Homeownership_D); TimeSeriesSimulationPlotter homeownershipStatusPlotter = new TimeSeriesSimulationPlotter("Share of benefit units owning homes", ""); homeownershipStatusPlotter.addSeries("Homeowners", new Weighted_MeanArrayFunction(homeownersBUsCS), null, colorArrayList.get(0), false); - homeownershipStatusPlotter.addSeries("Homeowners validation", validator, Validator.DoublesVariables.homeownership_BenefitUnit, colorArrayList.get(0), true); + if (showValidationStatistics) { + homeownershipStatusPlotter.addSeries("Homeowners validation", validator, Validator.DoublesVariables.homeownership_BenefitUnit, colorArrayList.get(0), true); + } homeownershipStatusPlotter.setName("Homeownership status"); updateChartSet.add(homeownershipStatusPlotter); tabSet.add(homeownershipStatusPlotter); @@ -686,6 +691,8 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer lowEducationCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getLowEducation", true); lowEducationCS.setFilter(ageFilter); + Weighted_CrossSection.Integer leftEducationCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getLeaveSchool", true); + leftEducationCS.setFilter(ageFilter); Weighted_CrossSection.Integer midEducationCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getMidEducation", true); midEducationCS.setFilter(ageFilter); Weighted_CrossSection.Integer highEducationCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getHighEducation", true); @@ -693,6 +700,7 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter eduAgePlotter = new TimeSeriesSimulationPlotter("Education level by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo() + "\n(excluding students)", ""); //'yo' means "years old" eduAgePlotter.addSeries("low", new Weighted_MeanArrayFunction(lowEducationCS), null, colorArrayList.get(0), false); + eduAgePlotter.addSeries("left educ", new Weighted_MeanArrayFunction(leftEducationCS), null, colorArrayList.get(3), false); eduAgePlotter.addSeries("mid", new Weighted_MeanArrayFunction(midEducationCS), null, colorArrayList.get(1), false); eduAgePlotter.addSeries("high", new Weighted_MeanArrayFunction(highEducationCS), null, colorArrayList.get(2), false); @@ -722,7 +730,9 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer regionCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getLowEducation", true); regionCS.setFilter(regionFilter); eduLowRegionPlotter.addSeries(region.getName(), new Weighted_MeanArrayFunction(regionCS), null, colorArrayList.get(colorCounter), false); //'yo' means "years old" - eduLowRegionPlotter.addSeries("Validation "+region.getName(), validator, Validator.DoublesVariables.valueOf("educationLevelLowByRegion_"+region), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + eduLowRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("educationLevelLowByRegion_" + region), colorArrayList.get(colorCounter), true); + } colorCounter++; } updateChartSet.add(eduLowRegionPlotter); //Add to set to be updated in buildSchedule method @@ -736,7 +746,9 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer regionCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getHighEducation", true); regionCS.setFilter(regionFilter); eduHighRegionPlotter.addSeries(region.getName(), new Weighted_MeanArrayFunction(regionCS), null, colorArrayList.get(colorCounter), false); //'yo' means "years old" - eduHighRegionPlotter.addSeries("Validation "+region.getName(), validator, Validator.DoublesVariables.valueOf("educationLevelHighByRegion_"+region), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + eduHighRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("educationLevelHighByRegion_" + region), colorArrayList.get(colorCounter), true); + } colorCounter++; } updateChartSet.add(eduHighRegionPlotter); //Add to set to be updated in buildSchedule method @@ -756,12 +768,16 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer regionCS = new Weighted_CrossSection.Integer(model.getBenefitUnits(), BenefitUnit.class, "getCoupleDummy", true); regionCS.setFilter(regionFilter); houseCompositionRegionPlotter.addSeries(region.getName(), new Weighted_MeanArrayFunction(regionCS), null, colorArrayList.get(colorCounter), false); //'yo' means "years old" - houseCompositionRegionPlotter.addSeries("Validation "+region.getName(), validator, Validator.DoublesVariables.valueOf("partneredShare_"+region), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + houseCompositionRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("partneredShare_" + region), colorArrayList.get(colorCounter), true); + } colorCounter++; } Weighted_CrossSection.Integer coupleCS = new Weighted_CrossSection.Integer(model.getBenefitUnits(), BenefitUnit.class, "getCoupleDummy", true); houseCompositionRegionPlotter.addSeries("national", new Weighted_MeanArrayFunction(coupleCS), null, colorArrayList.get(colorCounter), false); //'yo' means "years old" - houseCompositionRegionPlotter.addSeries("Validation national", validator, Validator.DoublesVariables.valueOf("partneredShare_All"), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + houseCompositionRegionPlotter.addSeries("Validation national", validator, Validator.DoublesVariables.valueOf("partneredShare_All"), colorArrayList.get(colorCounter), true); + } houseCompositionRegionPlotter.setName("Cohabitation status"); updateChartSet.add(houseCompositionRegionPlotter); //Add to set to be updated in buildSchedule method tabSet.add(houseCompositionRegionPlotter); @@ -851,8 +867,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter disabledAgePlotter = new TimeSeriesSimulationPlotter("Disability rate", ""); disabledAgePlotter.addSeries("males", new Weighted_MeanArrayFunction(maleCSDisabled), null, colorArrayList.get(0), false); disabledAgePlotter.addSeries("females", new Weighted_MeanArrayFunction(femaleCSDisabled), null, colorArrayList.get(1), false); - disabledAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("disabledMale"), colorArrayList.get(0), true); - disabledAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("disabledFemale"), colorArrayList.get(1), true); + if (showValidationStatistics) { + disabledAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("disabledMale"), colorArrayList.get(0), true); + disabledAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("disabledFemale"), colorArrayList.get(1), true); + } updateChartSet.add(disabledAgePlotter); disabledAgePlots.add(disabledAgePlotter); @@ -876,8 +894,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter healthAgePlotter = new TimeSeriesSimulationPlotter("Health score by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo(), ""); healthAgePlotter.addSeries("males", new Weighted_MeanArrayFunction(maleCS), null, colorArrayList.get(0), false); healthAgePlotter.addSeries("females", new Weighted_MeanArrayFunction(femaleCS), null, colorArrayList.get(1), false); - healthAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("healthMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); - healthAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("healthFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + if (showValidationStatistics) { + healthAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("healthMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); + healthAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("healthFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + } updateChartSet.add(healthAgePlotter); healthAgePlots.add(healthAgePlotter); @@ -900,8 +920,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter healthMentalAgePlotter = new TimeSeriesSimulationPlotter("Psychological distress score by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo(), ""); healthMentalAgePlotter.addSeries("males", new Weighted_MeanArrayFunction(maleCS), null, colorArrayList.get(0), false); healthMentalAgePlotter.addSeries("females", new Weighted_MeanArrayFunction(femaleCS), null, colorArrayList.get(1), false); - healthMentalAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("mentalHealthMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); - healthMentalAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("mentalHealthFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + if (showValidationStatistics) { + healthMentalAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("mentalHealthMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); + healthMentalAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("mentalHealthFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + } updateChartSet.add(healthMentalAgePlotter); healthMentalAgePlots.add(healthMentalAgePlotter); @@ -924,8 +946,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter psychDistressAgePlotter = new TimeSeriesSimulationPlotter("Share in psychological distress by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo(), ""); psychDistressAgePlotter.addSeries("males", new Weighted_MeanArrayFunction(maleCS), null, colorArrayList.get(0), false); psychDistressAgePlotter.addSeries("females", new Weighted_MeanArrayFunction(femaleCS), null, colorArrayList.get(1), false); - psychDistressAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("psychDistressMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); - psychDistressAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("psychDistressFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + if (showValidationStatistics) { + psychDistressAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("psychDistressMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); + psychDistressAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("psychDistressFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + } updateChartSet.add(psychDistressAgePlotter); psychologicalDistressCasesAgePlots.add(psychDistressAgePlotter); @@ -950,8 +974,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter psychDistressAgeEducationPlotter = new TimeSeriesSimulationPlotter("Share in psychological distress by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo(), ""); psychDistressAgeEducationPlotter.addSeries("males " + education + " educ", new Weighted_MeanArrayFunction(maleCS), null, colorArrayList.get(0), false); psychDistressAgeEducationPlotter.addSeries("females " + education + " educ", new Weighted_MeanArrayFunction(femaleCS), null, colorArrayList.get(1), false); - psychDistressAgeEducationPlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("psychDistressMale_"+ageFrom+"_"+ageTo), colorArrayList.get(0), true); - psychDistressAgeEducationPlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("psychDistressFemale_"+ageFrom+"_"+ageTo), colorArrayList.get(1), true); + if (showValidationStatistics) { + psychDistressAgeEducationPlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("psychDistressMale_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); + psychDistressAgeEducationPlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("psychDistressFemale_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + } updateChartSet.add(psychDistressAgeEducationPlotter); psychologicalDistressCasesAgeEducationPlots.add(psychDistressAgeEducationPlotter); } @@ -1052,8 +1078,10 @@ else if(edu.equals(Education.High)) { emplPlotter.addSeries("males", new Weighted_MeanArrayFunction(males18_64CS), null, colorArrayList.get(0), false); // emplPlotter.addSeries("males_NE", new Weighted_MeanArrayFunction(males18_64CSNE)); emplPlotter.addSeries("females", new Weighted_MeanArrayFunction(females18_64CS), null, colorArrayList.get(1), false); - emplPlotter.addSeries("Validation males", validator, Validator.DoublesVariables.employmentMale, colorArrayList.get(0), true); - emplPlotter.addSeries("Validation females", validator, Validator.DoublesVariables.employmentFemale, colorArrayList.get(1), true); + if (showValidationStatistics) { + emplPlotter.addSeries("Validation males", validator, Validator.DoublesVariables.employmentMale, colorArrayList.get(0), true); + emplPlotter.addSeries("Validation females", validator, Validator.DoublesVariables.employmentFemale, colorArrayList.get(1), true); + } emplPlotter.setName("Employment"); updateChartSet.add(emplPlotter); //Add to set to be updated in buildSchedule method @@ -1079,8 +1107,10 @@ else if(edu.equals(Education.High)) { TimeSeriesSimulationPlotter emplAgePlotter = new TimeSeriesSimulationPlotter("Employment rate by age: " + ageFilter.getAgeFrom() + " - " + ageFilter.getAgeTo(), ""); emplAgePlotter.addSeries("males", new Weighted_MeanArrayFunction(maleCS), null, colorArrayList.get(0), false); emplAgePlotter.addSeries("females", new Weighted_MeanArrayFunction(femaleCS), null, colorArrayList.get(1), false); - emplAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("employmentMaleByAge_"+ageFrom+"_"+ageTo), colorArrayList.get(0), true); - emplAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("employmentFemaleByAge_"+ageFrom+"_"+ageTo), colorArrayList.get(1), true); + if (showValidationStatistics) { + emplAgePlotter.addSeries("Validation males", validator, Validator.DoublesVariables.valueOf("employmentMaleByAge_" + ageFrom + "_" + ageTo), colorArrayList.get(0), true); + emplAgePlotter.addSeries("Validation females", validator, Validator.DoublesVariables.valueOf("employmentFemaleByAge_" + ageFrom + "_" + ageTo), colorArrayList.get(1), true); + } updateChartSet.add(emplAgePlotter); //Add to set to be updated in buildSchedule method emplAgePlots.add(emplAgePlotter); } @@ -1137,9 +1167,11 @@ else if(edu.equals(Education.High)) { emplChildPlotter.addSeries("with children aged 0 - 5 yo", new Weighted_MeanArrayFunction(withChildrenAged0_5CS), null, colorArrayList.get(0), false); emplChildPlotter.addSeries("with children aged 6 - 18 yo", new Weighted_MeanArrayFunction(withChildrenAged6_18CS), null, colorArrayList.get(1), false); emplChildPlotter.addSeries("without children under 18 yo", new Weighted_MeanArrayFunction(withoutChildrenCS), null, colorArrayList.get(2), false); - emplChildPlotter.addSeries("Validation with children aged 0 - 5 yo", validator, Validator.DoublesVariables.employmentFemaleChild_0_5, colorArrayList.get(0), true); - emplChildPlotter.addSeries("Validation with children aged 6 - 18 yo", validator, Validator.DoublesVariables.employmentFemaleChild_6_18, colorArrayList.get(1), true); - emplChildPlotter.addSeries("Validation without children under 18 yo", validator, Validator.DoublesVariables.employmentFemaleNoChild, colorArrayList.get(2), true); + if (showValidationStatistics) { + emplChildPlotter.addSeries("Validation with children aged 0 - 5 yo", validator, Validator.DoublesVariables.employmentFemaleChild_0_5, colorArrayList.get(0), true); + emplChildPlotter.addSeries("Validation with children aged 6 - 18 yo", validator, Validator.DoublesVariables.employmentFemaleChild_6_18, colorArrayList.get(1), true); + emplChildPlotter.addSeries("Validation without children under 18 yo", validator, Validator.DoublesVariables.employmentFemaleNoChild, colorArrayList.get(2), true); + } updateChartSet.add(emplChildPlotter); //Add to set to be updated in buildSchedule method emplAgeMaternityPlots.add(emplChildPlotter); @@ -1176,14 +1208,18 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Integer maleRegionCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getEmployed", true); maleRegionCS.setFilter(maleRegionFilter); emplMaleRegionPlotter.addSeries(region.getName(), new Weighted_MeanArrayFunction(maleRegionCS), null, colorArrayList.get(colorCounter), false); - emplMaleRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("employed_male_"+region), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + emplMaleRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("employed_male_" + region), colorArrayList.get(colorCounter), true); + } // FemaleRegionCSfilter femaleRegionFilter = new FemaleRegionCSfilter(region); FemaleRegionAgeCSfilter femaleRegionFilter = new FemaleRegionAgeCSfilter(region, 18, 64); Weighted_CrossSection.Integer femaleRegionCS = new Weighted_CrossSection.Integer(model.getPersons(), Person.class, "getEmployed", true); femaleRegionCS.setFilter(femaleRegionFilter); emplFemaleRegionPlotter.addSeries(region.getName(), new Weighted_MeanArrayFunction(femaleRegionCS), null, colorArrayList.get(colorCounter), false); - emplFemaleRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("employed_female_"+region), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + emplFemaleRegionPlotter.addSeries("Validation " + region.getName(), validator, Validator.DoublesVariables.valueOf("employed_female_" + region), colorArrayList.get(colorCounter), true); + } colorCounter++; } updateChartSet.add(emplMaleRegionPlotter); //Add to set to be updated in buildSchedule method @@ -1202,7 +1238,9 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Double supplyCS = new Weighted_CrossSection.Double(model.getPersons(), Person.class, "getLabourSupplyHoursYearly", true); supplyCS.setFilter(eduFilter); supplyPlotter.addSeries(edu.toString(), new Weighted_MeanArrayFunction(supplyCS), null, colorArrayList.get(colorCounter), false); - supplyPlotter.addSeries("Validation " + edu.toString(), validator, Validator.DoublesVariables.valueOf("labour_supply_"+edu), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + supplyPlotter.addSeries("Validation " + edu.toString(), validator, Validator.DoublesVariables.valueOf("labour_supply_" + edu), colorArrayList.get(colorCounter), true); + } colorCounter++; } supplyPlotter.setName("Labour supply"); @@ -1213,12 +1251,9 @@ else if(edu.equals(Education.High)) { //INCOME CHARTS - GROSS WAGES BY REGION AND EDUCATION LEVEL if(grossEarningsByRegionAndEducation) { IndividualBarSimulationPlotter earningsPlotter; - if (model.getCountry().equals(Country.UK)) { - earningsPlotter = new IndividualBarSimulationPlotter("Yearly Gross Earnings by Education and Region (excludes non-workers)", "£"); - } - else { + earningsPlotter = new IndividualBarSimulationPlotter("Yearly Gross Earnings by Education and Region (excludes non-workers)", "Euro"); - } + for(Region region: Parameters.getCountryRegions()) { for(Education edu: Education.values()) { @@ -1237,19 +1272,17 @@ else if(edu.equals(Education.High)) { if (grossEarningsByRegionAndEducation) { TimeSeriesSimulationPlotter grossEarningsByGenderAndEducationPlotter; int colorCounter = 0; - if (model.getCountry().equals(Country.UK)) { - grossEarningsByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Yearly Gross Earnings by Gender And Education", "£"); - } - else { - grossEarningsByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Yearly Gross Earnings by Gender And Education", "Euro"); - } + grossEarningsByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Yearly Gross Earnings by Gender And Education", "Euro"); + for(Education edu: Education.values()) { for (Gender gender : Gender.values()) { GenderEducationWorkingCSfilter genderEducationWorkingFilter = new GenderEducationWorkingCSfilter(gender, edu); Weighted_CrossSection.Double wagesCS = new Weighted_CrossSection.Double(model.getPersons(), Person.class, "getGrossEarningsYearly", true); // Note: these are nominal values for each simulated year wagesCS.setFilter(genderEducationWorkingFilter); grossEarningsByGenderAndEducationPlotter.addSeries("(" + gender.toString() + ", " + edu.toString() + ")", new Weighted_MeanArrayFunction(wagesCS), null, colorArrayList.get(colorCounter), false); - grossEarningsByGenderAndEducationPlotter.addSeries("Validation (" + gender + ", " + edu + ")", validator, Validator.DoublesVariables.valueOf("grossEarnings_"+ gender +"_"+ edu), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + grossEarningsByGenderAndEducationPlotter.addSeries("Validation (" + gender + ", " + edu + ")", validator, Validator.DoublesVariables.valueOf("grossEarnings_" + gender + "_" + edu), colorArrayList.get(colorCounter), true); + } colorCounter++; } } @@ -1261,19 +1294,17 @@ else if(edu.equals(Education.High)) { if (grossEarningsByRegionAndEducation) { TimeSeriesSimulationPlotter hourlyWagesByGenderAndEducationPlotter; int colorCounter = 0; - if (model.getCountry().equals(Country.UK)) { - hourlyWagesByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Hourly Wages by Gender And Education", "£"); - } - else { - hourlyWagesByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Hourly Wages by Gender And Education", "Euro"); - } + hourlyWagesByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Hourly Wages by Gender And Education", "Euro"); + for(Education edu: Education.values()) { for (Gender gender : Gender.values()) { GenderEducationWorkingCSfilter genderEducationWorkingFilter = new GenderEducationWorkingCSfilter(gender, edu); Weighted_CrossSection.Double wagesCS = new Weighted_CrossSection.Double(model.getPersons(), Person.class, "getHourlyWageRate1", true); // Note: these are nominal values for each simulated year wagesCS.setFilter(genderEducationWorkingFilter); hourlyWagesByGenderAndEducationPlotter.addSeries("(" + gender.toString() + ", " + edu.toString() + ")", new Weighted_MeanArrayFunction(wagesCS), null, colorArrayList.get(colorCounter), false); - hourlyWagesByGenderAndEducationPlotter.addSeries("Validation (" + gender + ", " + edu + ")", validator, Validator.DoublesVariables.valueOf("hourlyWage_"+ gender +"_"+ edu), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + hourlyWagesByGenderAndEducationPlotter.addSeries("Validation (" + gender + ", " + edu + ")", validator, Validator.DoublesVariables.valueOf("hourlyWage_" + gender + "_" + edu), colorArrayList.get(colorCounter), true); + } colorCounter++; } } @@ -1291,7 +1322,9 @@ else if(edu.equals(Education.High)) { Weighted_CrossSection.Double hoursCS = new Weighted_CrossSection.Double(model.getPersons(), Person.class, "getDoubleLabourSupplyHoursWeekly", true); // Note: these are nominal values for each simulated year hoursCS.setFilter(genderWorkingFilter); hoursOfWorkByGenderPlotter.addSeries(gender.toString(), new Weighted_MeanArrayFunction(hoursCS), null, colorArrayList.get(colorCounter), false); - hoursOfWorkByGenderPlotter.addSeries("Validation " + gender, validator, Validator.DoublesVariables.valueOf("lhw_"+ gender), colorArrayList.get(colorCounter), true); + if (showValidationStatistics) { + hoursOfWorkByGenderPlotter.addSeries("Validation " + gender, validator, Validator.DoublesVariables.valueOf("lhw_" + gender), colorArrayList.get(colorCounter), true); + } colorCounter++; } hoursOfWorkByGenderPlotter.setName("Hours of Work by Gender"); @@ -1395,12 +1428,8 @@ else if(edu.equals(Education.High)) { if (incomeHistograms) { TimeSeriesSimulationPlotter EDIByGenderAndEducationPlotter; int colorCounter = 0; - if (model.getCountry().equals(Country.UK)) { - EDIByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("EDI by Gender And Education", "£"); - } - else { - EDIByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("EDI by Gender And Education", "Euro"); - } + EDIByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("EDI by Gender And Education", "Euro"); + for(Education edu: Education.values()) { for (Gender gender : Gender.values()) { GenderEducationWorkingCSfilter genderEducationWorkingFilter = new GenderEducationWorkingCSfilter(gender, edu); @@ -1424,12 +1453,8 @@ else if(edu.equals(Education.High)) { if (incomeHistograms) { TimeSeriesSimulationPlotter DispIncByGenderAndEducationPlotter; int colorCounter = 0; - if (model.getCountry().equals(Country.UK)) { - DispIncByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Disp income by Gender And Education", "£"); - } - else { - DispIncByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Disp income by Gender And Education", "Euro"); - } + DispIncByGenderAndEducationPlotter = new TimeSeriesSimulationPlotter("Disp income by Gender And Education", "Euro"); + for(Education edu: Education.values()) { for (Gender gender : Gender.values()) { GenderEducationWorkingCSfilter genderEducationWorkingFilter = new GenderEducationWorkingCSfilter(gender, edu); diff --git a/src/main/java/simpaths/experiment/SimPathsStart.java b/src/main/java/simpaths/experiment/SimPathsStart.java index 62b004911..34da9ab51 100644 --- a/src/main/java/simpaths/experiment/SimPathsStart.java +++ b/src/main/java/simpaths/experiment/SimPathsStart.java @@ -42,7 +42,7 @@ public class SimPathsStart implements ExperimentBuilder { // default simulation parameters - private static Country country = Country.UK; + private static Country country = Country.IT; private static int startYear = Parameters.getMaxStartYear(); private static boolean showGui = true; // Show GUI by default @@ -86,8 +86,7 @@ public static void main(String[] args) { if (lastDatabaseCountryAndYear.keySet().stream().anyMatch(key -> key.toString().equals("MultiKey[IT]"))) { country = Country.IT; } else { - country = Country.UK; -// country = Country.IT; + throw new IllegalArgumentException("Country not recognised. Restart the simulation and choose one of the available countries."); } String valueYear = lastDatabaseCountryAndYear.getValue(country.toString()).toString(); startYear = Integer.parseInt(valueYear); @@ -464,7 +463,6 @@ private static void chooseCountryAndStartYear() { // the country if possible. Could this be done by making the setCountry method ineffective // when the country has been set by the user in the dialog box in the start class? country = cbCountry.getCountryEnum(); //Temporarily commented out to disallow choice of the country - //country = Country.IT; startYear = cbStartYear.getYear(); //Save the last selected country and year to Excel to use in the model if GUI launched straight away diff --git a/src/main/java/simpaths/model/ActivityAlignment.java b/src/main/java/simpaths/model/ActivityAlignment.java index 1816967c7..7b3293301 100644 --- a/src/main/java/simpaths/model/ActivityAlignment.java +++ b/src/main/java/simpaths/model/ActivityAlignment.java @@ -44,8 +44,17 @@ public ActivityAlignment(Set persons, Set benefitUnits, Mul this.regressor2ToModify = null; this.originalRegressionCoefficient2 = 0; this.regressionCoefficientsMap = originalRegressionCoefficientsMap; - Object[] valuesOriginalCopy = (Object[]) originalRegressionCoefficientsMap.getValue(regressorToModify); - this.originalRegressionCoefficient = ((Number) valuesOriginalCopy[0]).doubleValue(); + + Object coefficientObj = originalRegressionCoefficientsMap.getValue(regressorToModify); + if (coefficientObj instanceof Object[]) { + Object[] valuesOriginalCopy = (Object[]) coefficientObj; + this.originalRegressionCoefficient = ((Number) valuesOriginalCopy[0]).doubleValue(); + } else if (coefficientObj instanceof Number) { + this.originalRegressionCoefficient = ((Number) coefficientObj).doubleValue(); + } else { + throw new IllegalArgumentException("Unexpected type: " + coefficientObj.getClass()); + } + this.benefitUnitType = benefitUnitType; // Share of employed benefit unit of a particular type (Single man / single woman / couple). Couple BU counts as employed if either of the responsible persons works. @@ -55,8 +64,15 @@ public ActivityAlignment(Set persons, Set benefitUnits, Mul case Couple -> { targetAggregateShareOfEmployedBU = Parameters.getTargetShare(model.getYear(), TargetShares.EmploymentCouples); regressor2ToModify = regressorsToModify[1]; - Object[] valuesOriginalCopy2 = (Object[]) originalRegressionCoefficientsMap.getValue(regressor2ToModify); - this.originalRegressionCoefficient2 = ((Number) valuesOriginalCopy2[0]).doubleValue(); + Object coefficientObj2 = originalRegressionCoefficientsMap.getValue(regressor2ToModify); + if (coefficientObj2 instanceof Object[]) { + Object[] valuesOriginalCopy2 = (Object[]) coefficientObj2; + this.originalRegressionCoefficient2 = ((Number) valuesOriginalCopy2[0]).doubleValue(); + } else if (coefficientObj2 instanceof Number) { + this.originalRegressionCoefficient2 = ((Number) coefficientObj2).doubleValue(); + } else { + throw new IllegalArgumentException("Unexpected type: " + coefficientObj2.getClass()); + } } } } @@ -109,19 +125,38 @@ private void adjustEmployment(double newUtilityAdjustment) { String regressionCoefficientKey = regressorToModify; // Name of the regressor to modify MultiKeyCoefficientMap map = regressionCoefficientsMap; // Map of regressors and estimated coefficients - Object[] currentValues = (Object[]) map.getValue(regressionCoefficientKey); - double newValue = originalRegressionCoefficient + newUtilityAdjustment; // Adjust regression coefficient - currentValues[0] = newValue; - map.replaceValue(regressionCoefficientKey, currentValues); // Put adjusted value back in the map + + // Retrieve current value from the map + Object currentValueObj = map.getValue(regressionCoefficientKey); + if (!(currentValueObj instanceof Number)) { + throw new IllegalArgumentException("Expected a numeric value for key: " + regressionCoefficientKey); + } + + // Adjust regression coefficient + double currentValue = ((Number) currentValueObj).doubleValue(); + double newValue = originalRegressionCoefficient + newUtilityAdjustment; + + // Replace adjusted value back in the map + map.replaceValue(regressionCoefficientKey, newValue); if (regressor2ToModify != null) { - String regressionCoefficientKey2 = regressor2ToModify; // Name of the regressor to modify - Object[] currentValues2 = (Object[]) map.getValue(regressionCoefficientKey2); - double newValue2 = originalRegressionCoefficient2 + newUtilityAdjustment; // Adjust regression coefficient - currentValues2[0] = newValue2; - map.replaceValue(regressionCoefficientKey2, currentValues2); // Put adjusted value back in the map + String regressionCoefficientKey2 = regressor2ToModify; // Name of the second regressor to modify + + // Retrieve current value for the second regressor + Object currentValueObj2 = map.getValue(regressionCoefficientKey2); + if (!(currentValueObj2 instanceof Number)) { + throw new IllegalArgumentException("Expected a numeric value for key: " + regressionCoefficientKey2); + } + + // Adjust regression coefficient for the second regressor + double currentValue2 = ((Number) currentValueObj2).doubleValue(); + double newValue2 = originalRegressionCoefficient2 + newUtilityAdjustment; + + // Replace adjusted value back in the map + map.replaceValue(regressionCoefficientKey2, newValue2); } + benefitUnits.parallelStream() .filter(BenefitUnit::getAtRiskOfWork) .filter(benefitUnit -> benefitUnit.getOccupancy().equals(benefitUnitType)) diff --git a/src/main/java/simpaths/model/ActivityAlignmentMacroShock.java b/src/main/java/simpaths/model/ActivityAlignmentMacroShock.java new file mode 100644 index 000000000..f9ef0a510 --- /dev/null +++ b/src/main/java/simpaths/model/ActivityAlignmentMacroShock.java @@ -0,0 +1,102 @@ +package simpaths.model; + +import microsim.data.MultiKeyCoefficientMap; +import microsim.engine.SimulationEngine; +import simpaths.data.IEvaluation; +import simpaths.data.Parameters; +import simpaths.model.enums.OccupancyMacroShock; +import simpaths.model.enums.TargetShares; +import simpaths.model.enums.Les_c4; + +import java.util.*; + +public class ActivityAlignmentMacroShock implements IEvaluation { + + private final double targetAggregateShareOfEmployedPersons; + private double utilityAdjustment; + boolean utilityAdjustmentChanged; + private final Map coefficientMaps; + private final Map> regressorsToModify; + private final Set persons; + private final Set benefitUnits; + private final SimPathsModel model; + + // Stores original values of coefficients that will be modified + private final Map> originalCoefficients; + + public ActivityAlignmentMacroShock(Set persons, Set benefitUnits, + Map coefficientMaps, + Map> regressorsToModify, + double utilityAdjustment) { + this.model = (SimPathsModel) SimulationEngine.getInstance().getManager(SimPathsModel.class.getCanonicalName()); + this.persons = Collections.unmodifiableSet(persons); + this.benefitUnits = Collections.unmodifiableSet(benefitUnits); + this.utilityAdjustment = utilityAdjustment; + this.coefficientMaps = Collections.unmodifiableMap(coefficientMaps); + this.regressorsToModify = Collections.unmodifiableMap(regressorsToModify); + + // Store original values of coefficients that will be modified + this.originalCoefficients = new EnumMap<>(OccupancyMacroShock.class); + for (Map.Entry> entry : regressorsToModify.entrySet()) { + OccupancyMacroShock occupancy = entry.getKey(); + List regressors = entry.getValue(); + MultiKeyCoefficientMap coefficientMap = coefficientMaps.get(occupancy); + + Map occupancyValues = new HashMap<>(); + for (String regressor : regressors) { + Object value = coefficientMap.getValue(regressor); + if (!(value instanceof Number)) { + throw new IllegalArgumentException("Coefficient " + regressor + " must be numeric"); + } + occupancyValues.put(regressor, ((Number) value).doubleValue()); + } + originalCoefficients.put(occupancy, occupancyValues); + } + + this.targetAggregateShareOfEmployedPersons = Parameters.getTargetShare(model.getYear(), TargetShares.Employment); + } + + @Override + public double evaluate(double[] args) { + adjustEmployment(args[0]); + return targetAggregateShareOfEmployedPersons - evalAggregateShareOfEmployedPersons(); + } + + private double evalAggregateShareOfEmployedPersons() { + long total = persons.size(); + if (total == 0) return 0.0; + + long employed = persons.stream() + .filter(p -> p.getLes_c4() == Les_c4.EmployedOrSelfEmployed) + .count(); + + return (double) employed / total; + } + + private void adjustEmployment(double newUtilityAdjustment) { + for (Map.Entry entry : coefficientMaps.entrySet()) { + OccupancyMacroShock occupancy = entry.getKey(); + MultiKeyCoefficientMap currentMap = entry.getValue(); + List regressors = regressorsToModify.get(occupancy); + Map originalValues = originalCoefficients.get(occupancy); + + for (String regressor : regressors) { + double originalValue = originalValues.get(regressor); + double newValue = originalValue + newUtilityAdjustment; + currentMap.replaceValue(regressor, newValue); + } + } + + // Update benefit units + benefitUnits.parallelStream() + .filter(BenefitUnit::getAtRiskOfWork) + .forEach(BenefitUnit::updateLabourSupplyAndIncome); + + benefitUnits.parallelStream() + .forEach(BenefitUnit::updateActivityOfPersonsWithinBenefitUnit); + + // Update state + utilityAdjustment = newUtilityAdjustment; + utilityAdjustmentChanged = true; + } +} diff --git a/src/main/java/simpaths/model/ActivityAlignmentV2.java b/src/main/java/simpaths/model/ActivityAlignmentV2.java new file mode 100644 index 000000000..25faa5d0b --- /dev/null +++ b/src/main/java/simpaths/model/ActivityAlignmentV2.java @@ -0,0 +1,154 @@ +package simpaths.model; + +import microsim.data.MultiKeyCoefficientMap; +import microsim.engine.SimulationEngine; +import simpaths.data.IEvaluation; +import simpaths.data.Parameters; +import simpaths.model.enums.Occupancy; +import simpaths.model.enums.TargetShares; + +import java.util.*; + +/** + * ActivityAlignmentV2 calibrates a labor supply model by adjusting utility function coefficients, + * so that the simulated employment rate for a specific household (benefit unit) type + * matches a target employment rate from empirical data. + */ +public class ActivityAlignmentV2 implements IEvaluation { + + private final double targetAggregateShareOfEmployed; + private final Map originalCoefficients; + private final MultiKeyCoefficientMap coefficientMap; + private final List regressorsToModify; + private final Set benefitUnits; + private final Occupancy benefitUnitType; + private final SimPathsModel model; + + public ActivityAlignmentV2(Set benefitUnits, + MultiKeyCoefficientMap coefficientMap, + String[] regressorsToModify, + Occupancy benefitUnitType) { + this.model = (SimPathsModel) SimulationEngine.getInstance() + .getManager(SimPathsModel.class.getCanonicalName()); + this.benefitUnits = Collections.unmodifiableSet(benefitUnits); + this.coefficientMap = coefficientMap; + this.regressorsToModify = Arrays.asList(regressorsToModify.clone()); + this.benefitUnitType = benefitUnitType; + this.originalCoefficients = extractOriginalCoefficients(coefficientMap, this.regressorsToModify); + this.targetAggregateShareOfEmployed = determineTargetShare(model, benefitUnitType); + } + + /** + * Extracts the original values of the coefficients to be adjusted. + * Handles both numeric values and single-element arrays of numbers. + */ + private Map extractOriginalCoefficients(MultiKeyCoefficientMap map, List regressors) { + Map originals = new LinkedHashMap<>(); + for (String regressor : regressors) { + Object value = map.getValue(regressor); + if (value instanceof Number num) { + originals.put(regressor, new CoefficientValue(num.doubleValue())); + } else if (value instanceof Object[] arr && arr.length > 0 && arr[0] instanceof Number num) { + originals.put(regressor, new CoefficientValue(arr, num.doubleValue())); + } else { + String type = value != null ? value.getClass().getSimpleName() : "null"; + throw new IllegalArgumentException( + "Regressor '" + regressor + "' must be numeric or a numeric array but is " + type + " (value: " + value + ")" + ); + } + } + return originals; + } + + /** + * Determines the target employment share for the given benefit unit type and simulation year. + */ + private double determineTargetShare(SimPathsModel model, Occupancy type) { + switch (type) { + case Couple: + return Parameters.getTargetShare(model.getYear(), TargetShares.EmploymentCouples); + case Single_Male: + return Parameters.getTargetShare(model.getYear(), TargetShares.EmploymentSingleMales); + case Single_Female: + return Parameters.getTargetShare(model.getYear(), TargetShares.EmploymentSingleFemales); + default: + throw new IllegalArgumentException("Unsupported occupancy type: " + type); + } + } + + /** + * Applies a utility adjustment, updates the model, and returns the difference between + * target and simulated employment shares. + */ + @Override + public double evaluate(double[] args) { + double newUtilityAdjustment = args[0]; + adjustEmployment(newUtilityAdjustment); + return targetAggregateShareOfEmployed - evalAggregateShareOfEmployedBU(); + } + + /** + * Efficiently computes the employment rate for benefit units of the specified type. + */ + private double evalAggregateShareOfEmployedBU() { + long[] counts = benefitUnits.stream() + .filter(bu -> bu.getOccupancy().equals(benefitUnitType)) + .collect(() -> new long[2], + (arr, bu) -> { + arr[0]++; + if (bu.isEmployed()) arr[1]++; + }, + (a, b) -> { + a[0] += b[0]; + a[1] += b[1]; + }); + return counts[0] > 0 ? (double) counts[1] / counts[0] : 0.0; + } + + /** + * Adjusts the specified utility coefficients by the given amount, + * always relative to their original values, and updates all benefit units. + */ + private void adjustEmployment(double newUtilityAdjustment) { + for (String regressor : regressorsToModify) { + CoefficientValue original = originalCoefficients.get(regressor); + Object newValue; + if (original.isArray()) { + Object[] newArr = Arrays.copyOf(original.arrayValue, original.arrayValue.length); + newArr[0] = original.baseValue + newUtilityAdjustment; + newValue = newArr; + } else { + newValue = original.baseValue + newUtilityAdjustment; + } + coefficientMap.replaceValue(regressor, newValue); + } + + // Update benefit units in a single parallel pass for efficiency + benefitUnits.parallelStream().forEach(bu -> { + bu.updateLabourSupplyAndIncome(); + bu.updateActivityOfPersonsWithinBenefitUnit(); + }); + } + + /** + * Helper class to track coefficient types and values. + */ + private static class CoefficientValue { + final double baseValue; + final Object[] arrayValue; + + CoefficientValue(double scalar) { + this.baseValue = scalar; + this.arrayValue = null; + } + + CoefficientValue(Object[] array, double firstElement) { + this.baseValue = firstElement; + this.arrayValue = array; + } + + boolean isArray() { + return arrayValue != null; + } + } +} diff --git a/src/main/java/simpaths/model/BenefitUnit.java b/src/main/java/simpaths/model/BenefitUnit.java index e228420ca..7ba6440b8 100644 --- a/src/main/java/simpaths/model/BenefitUnit.java +++ b/src/main/java/simpaths/model/BenefitUnit.java @@ -1,14 +1,11 @@ package simpaths.model; -import java.util.*; - import jakarta.persistence.*; - +import microsim.agent.Weight; import microsim.data.db.PanelEntityKey; -import simpaths.data.ManagerRegressions; -import simpaths.data.MultiValEvent; -import simpaths.data.filters.ValidHomeownersCSfilter; -import simpaths.model.enums.*; +import microsim.engine.SimulationEngine; +import microsim.event.EventListener; +import microsim.statistics.IDoubleSource; import org.apache.commons.collections4.keyvalue.MultiKey; import org.apache.commons.collections4.map.LinkedMap; import org.apache.commons.collections4.map.MultiKeyMap; @@ -16,18 +13,17 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.tuple.Triple; import org.apache.log4j.Logger; - +import simpaths.data.ManagerRegressions; import simpaths.data.Parameters; +import simpaths.data.filters.ValidHomeownersCSfilter; +import simpaths.experiment.SimPathsCollector; import simpaths.model.decisions.DecisionParams; import simpaths.model.decisions.States; -import simpaths.experiment.SimPathsCollector; -import microsim.agent.Weight; -import microsim.engine.SimulationEngine; -import microsim.event.EventListener; -import microsim.statistics.IDoubleSource; -import simpaths.model.enums.Les_c4; +import simpaths.model.enums.*; import simpaths.model.taxes.Match; +import java.util.*; + import static java.lang.StrictMath.min; @Entity @@ -86,9 +82,11 @@ public class BenefitUnit implements EventListener, IDoubleSource, Weight, Compar @Enumerated(EnumType.STRING) private Ydses_c5 ydses_c5; @Transient private Ydses_c5 ydses_c5_lag1; @Transient private Double tmpHHYpnbihs_dv_asinh; + private Dhhtp_c4 dhhtp_c4; @Transient private Dhhtp_c4 dhhtp_c4_lag1; private String createdByConstructor; @Column(name="dhh_owned") private Boolean dhhOwned; // are any of the individuals in the benefit unit a homeowner? True / false + @Transient private Boolean dhhOwned_lag1; @Transient ArrayList> covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale = new ArrayList<>(); @Transient ArrayList> covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale = new ArrayList<>(); // This ArrayList stores monthly values of labour market states and gross incomes, to be sampled from by the LabourMarket class, for the female member of the benefit unit @@ -262,6 +260,7 @@ public BenefitUnit(BenefitUnit originalBenefitUnit, long benefitUnitInnov, Sampl this.ydses_c5_lag1 = originalBenefitUnit.ydses_c5_lag1; this.dhhtp_c4_lag1 = originalBenefitUnit.dhhtp_c4_lag1; this.dhhOwned = originalBenefitUnit.dhhOwned; + this.dhhOwned_lag1 = originalBenefitUnit.dhhOwned_lag1; createdByConstructor = Objects.requireNonNullElse(originalBenefitUnit.createdByConstructor,"CopyConstructor"); tmpHHYpnbihs_dv_asinh = Objects.requireNonNullElse(originalBenefitUnit.tmpHHYpnbihs_dv_asinh, 0.0); taxDbMatch = originalBenefitUnit.getTaxDbMatch(); @@ -275,6 +274,7 @@ public BenefitUnit(BenefitUnit originalBenefitUnit, long benefitUnitInnov, Sampl public enum Processes { Update, //This updates the household fields, such as number of children of a certain age + UpdateOutputVariables, UpdateWealth, CalculateChangeInEDI, //Calculate change in equivalised disposable income Homeownership, @@ -292,6 +292,9 @@ public void onEvent(Enum type) { updateAttributes(); clearStates(); } + case UpdateOutputVariables -> { + updateOutputVariables(); + } case UpdateWealth -> { updateWealth(); } @@ -343,6 +346,7 @@ protected void updateAttributes() { numberChildrenAll_lag1 = getNumberChildrenAll(); numberChildren02_lag1 = getNumberChildren(0,2); dhhtp_c4_lag1 = getDhhtp_c4(); + dhhOwned_lag1 = isDhhOwned(); equivalisedDisposableIncomeYearly_lag1 = getEquivalisedDisposableIncomeYearly(); atRiskOfPoverty_lag1 = getAtRiskOfPoverty(); @@ -356,6 +360,13 @@ protected void updateWealth() { liquidWealth += disposableIncomeMonthly * 12.0 - discretionaryConsumptionPerYear - getNonDiscretionaryConsumptionPerYear(); } + /* + Contemporaneous values of dhhtp_c4 are required for validation. Update and output here. + */ + private void updateOutputVariables() { + dhhtp_c4 = getDhhtp_c4(); + } + // --------------------------------------------------------------------- // Labour Market Interaction @@ -464,8 +475,8 @@ protected void updateDisposableIncomeIfNotAtRiskOfWork() { Person female = getFemale(); if (male!=null && female!=null) { - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM)); - getFemale().setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF)); + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM, Gender.Male)); + getFemale().setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF, Gender.Female)); double maleIncome = Math.sinh(male.getYptciihs_dv()); double femaleIncome = Math.sinh(getFemale().getYptciihs_dv()); if (maleIncome>0.01 && femaleIncome>0.01) @@ -475,12 +486,12 @@ protected void updateDisposableIncomeIfNotAtRiskOfWork() { dlltsdF = getFemale().getDisability(); } else if (male!=null) { - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM)); + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM, Gender.Male)); originalIncomePerMonth = Math.sinh(male.getYptciihs_dv()); dlltsdM = male.getDisability(); } else if (female!=null){ - getFemale().setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF)); + getFemale().setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF, Gender.Female)); originalIncomePerMonth = Math.sinh(getFemale().getYptciihs_dv()); dlltsdF = getFemale().getDisability(); } else @@ -531,30 +542,6 @@ private TaxEvaluation taxWrapper(double hoursWorkedPerWeekM, double hoursWorkedP return evaluatedTransfers; } - protected void updateMonthlyLabourSupplyCovid19() { - - // This method calls on predictCovidTransition() method to set labour market state, gross income, and work hours for each month. - // After 12 months, this should result in an array with 12 values, from which the LabourMarket class can sample one that is representative of the labour market state for the whole year. - Person male = getMale(); - Person female = getFemale(); - if (male!=null && female!=null) { - if (male.atRiskOfWork()) { - Triple stateGrossIncomeWorkHoursTriple = predictCovidTransition(male); // predictCovidTransition() applies transition models to predict transition and returns new labour market state, gross income, and work hours - covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale.add(stateGrossIncomeWorkHoursTriple); // Add the state-gross income-work hours triple to the ArrayList keeping track of all monthly values - } - if (female.atRiskOfWork()) { - Triple stateGrossIncomeWorkHoursTriple = predictCovidTransition(getFemale()); - covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale.add(stateGrossIncomeWorkHoursTriple); - } - } else if (male!=null || female!=null) { - Person person = Objects.requireNonNullElse(male,female); - if (person.atRiskOfWork()) { - Triple stateGrossIncomeWorkHoursTriple = predictCovidTransition(person); - covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale.add(stateGrossIncomeWorkHoursTriple); - } - } else {System.out.println("Warning: Incorrect occupancy for benefit unit " + getKey().getId());} - } - /* chooseRandomMonthlyTransitionAndGrossIncome() method selected a random value out of all the monthly transitions (which contains state to which individual transitions, gross income, and work hours), finds donor benefit unit and calculates disposable income @@ -585,8 +572,8 @@ protected void chooseRandomMonthlyOutcomeCovid19() { female.setLes_c4(Les_c4.convertLes_c7_To_Les_c4(selectedValueFemale.getLeft())); // Predicted hours need to be converted back into labour so a donor benefit unit can be found. Then, gross income can be converted to disposable. - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight())); // Convert predicted work hours to labour enum and update male's value - female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight())); // Convert predicted work hours to labour enum and update female's value + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight(), Gender.Male)); // Convert predicted work hours to labour enum and update male's value + female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight(), Gender.Female)); // Convert predicted work hours to labour enum and update female's value double simulatedIncomeToConvertPerMonth = selectedValueMale.getMiddle() + selectedValueFemale.getMiddle(); // Benefit unit's gross income to convert is the sum of incomes (labour and capital included) of male and female // Find best donor and convert gross income to disposable @@ -612,7 +599,7 @@ protected void chooseRandomMonthlyOutcomeCovid19() { male.setLes_c4(Les_c4.convertLes_c7_To_Les_c4(selectedValueMale.getLeft())); // Predicted hours need to be converted back into labour so a donor benefit unit can be found. Then, gross income can be converted to disposable. - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight())); // Convert predicted work hours to labour enum and update male's value + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight(), Gender.Male)); // Convert predicted work hours to labour enum and update male's value double simulatedIncomeToConvertPerMonth = selectedValueMale.getMiddle(); // Benefit unit's gross income to convert is the sum of incomes (labour and capital included) of male and female // Find best donor and convert gross income to disposable @@ -637,7 +624,7 @@ protected void chooseRandomMonthlyOutcomeCovid19() { female.setLes_c4(Les_c4.convertLes_c7_To_Les_c4(selectedValueFemale.getLeft())); // Predicted hours need to be converted back into labour so a donor benefit unit can be found. Then, gross income can be converted to disposable. - female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight())); // Convert predicted work hours to labour enum and update female's value + female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight(), Gender.Female)); // Convert predicted work hours to labour enum and update female's value double simulatedIncomeToConvertPerMonth = selectedValueFemale.getMiddle(); // Benefit unit's gross income to convert is the sum of incomes (labour and capital included) of male and female, but in this case male is not at risk of work // Find best donor and convert gross income to disposable @@ -660,7 +647,7 @@ protected void chooseRandomMonthlyOutcomeCovid19() { int randomIndex = intFromUniform(0, covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale.size(), labourInnov); Triple selectedValueMale = covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale.get(randomIndex); male.setLes_c7_covid(selectedValueMale.getLeft()); // Set labour force status for male - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight())); + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueMale.getRight(), Gender.Male)); double simulatedIncomeToConvertPerMonth = selectedValueMale.getMiddle(); // Find best donor and convert gross income to disposable @@ -680,7 +667,7 @@ protected void chooseRandomMonthlyOutcomeCovid19() { int randomIndex = intFromUniform(0, covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale.size(), labourInnov); Triple selectedValueFemale = covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale.get(randomIndex); female.setLes_c7_covid(selectedValueFemale.getLeft()); // Set labour force status for female - female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight())); + female.setLabourSupplyWeekly(Labour.convertHoursToLabour(selectedValueFemale.getRight(), Gender.Female)); double simulatedIncomeToConvertPerMonth = selectedValueFemale.getMiddle(); // Find best donor and convert gross income to disposable @@ -705,156 +692,6 @@ protected void chooseRandomMonthlyOutcomeCovid19() { It returns gross income at individual level, which is then totaled in the updateLabourSupplyCovid19() method above and gross income of the benefit unit and converted to disposable at the benefit unit level in the updateLabourSupplyCovid19() method above. */ - private Triple predictCovidTransition(Person person) { - - if (person.getLes_c7_covid_lag1() == null) { - person.initialise_les_c6_from_c4(); - person.setCovidModuleGrossLabourIncome_lag1(person.getCovidModuleGrossLabourIncome_Baseline()); - } - - - // Define variables: - Les_c7_covid stateFrom = person.getLes_c7_covid_lag1(); - Les_c7_covid stateTo = stateFrom; // Labour market state to which individual transitions. Initialise to stateFrom value if the outcome is "no changes" - int newWorkHours; // Predicted work hours. Initialise to previous value if available, or hours from labour enum. - if (person.getNewWorkHours_lag1() != null) { - newWorkHours = person.getNewWorkHours_lag1(); - } else { - newWorkHours = person.getLabourSupplyHoursWeekly(); // Note: prediction for hours is in logs, needs to be transformed to levels - person.setNewWorkHours_lag1(newWorkHours); - } - double grossMonthlyIncomeToReturn = 0; // Gross income to return to updateLabourSupplyCovid19() method - - // Transitions from employment - double labourInnov2 = innovations.getDoubleDraw(3), labourInnov3 = innovations.getDoubleDraw(4); - if (Les_c7_covid.Employee.equals(stateFrom)) { - Map probs = Parameters.getRegC19LS_E1().getProbabilites(person, Person.DoublesVariables.class, Les_transitions_E1.class); - MultiValEvent event = new MultiValEvent(probs, labourInnov2); - Les_transitions_E1 transitionTo = (Les_transitions_E1) event.eval(); - stateTo = transitionTo.convertToLes_c7_covid(); - person.setLes_c7_covid(stateTo); // Use convert to les c6 covid method from the enum to convert the outcome to the les c6 scale and update the variable - - if (Les_transitions_E1.SelfEmployed.equals(transitionTo) || Les_transitions_E1.SomeChanges.equals(transitionTo)) { - - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_E2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_E1.NotEmployed)) { - newWorkHours = 0; - grossMonthlyIncomeToReturn = 0; - } else if (transitionTo.equals(Les_transitions_E1.FurloughedFull)) { - // If furloughed, don't change hours of work initialised at the beginning - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_E1.FurloughedFlex)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_E2b().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else { // Else "no changes" = employee. Use initialisation value for stateTo and newWorkHours and fill gross monthly income - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } - - // Transitions from furlough full - } else if (stateFrom.equals(Les_c7_covid.FurloughedFull)) { - Map probs = Parameters.getRegC19LS_FF1().getProbabilites(person, Person.DoublesVariables.class, Les_transitions_FF1.class); - MultiValEvent event = new MultiValEvent(probs, labourInnov2); - Les_transitions_FF1 transitionTo = (Les_transitions_FF1) event.eval(); - - stateTo = transitionTo.convertToLes_c7_covid(); - person.setLes_c7_covid(stateTo); // Use convert to les c7 covid method from the enum to convert the outcome to the les c7 scale and update the variable - - if (transitionTo.equals(Les_transitions_FF1.Employee)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2b().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_FF1.SelfEmployed)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_FF1.FurloughedFlex)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2c().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_FF1.NotEmployed)) { - newWorkHours = 0; - grossMonthlyIncomeToReturn = 0; - } else { // Else remains furloughed. Use 80% of initialisation value for stateTo and newWorkHours and fill gross monthly income - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } - - // Transitions from furlough flex - } else if (stateFrom.equals(Les_c7_covid.FurloughedFlex)) { - Map probs = Parameters.getRegC19LS_FX1().getProbabilites(person, Person.DoublesVariables.class, Les_transitions_FX1.class); - MultiValEvent event = new MultiValEvent(probs, labourInnov2); - Les_transitions_FX1 transitionTo = (Les_transitions_FX1) event.eval(); - stateTo = transitionTo.convertToLes_c7_covid(); - person.setLes_c7_covid(stateTo); // Use convert to les c7 covid method from the enum to convert the outcome to the les c7 scale and update the variable - - if (transitionTo.equals(Les_transitions_FX1.Employee)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2b().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_FX1.SelfEmployed)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_FX1.FurloughedFull)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_F2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); // 80% of earnings they would have had working normal hours, hence hours predicted as for employed in the line above - } else if (transitionTo.equals(Les_transitions_FX1.NotEmployed)) { - newWorkHours = 0; - grossMonthlyIncomeToReturn = 0; - } else { // Else remains furloughed. Use 80% of initialisation value for stateTo and newWorkHours and fill gross monthly income - grossMonthlyIncomeToReturn = 0.8 * Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } - - // Transitions from self-employment - } else if (stateFrom.equals(Les_c7_covid.SelfEmployed)) { - Map probs = Parameters.getRegC19LS_S1().getProbabilites(person, Person.DoublesVariables.class, Les_transitions_S1.class); - MultiValEvent event = new MultiValEvent(probs, labourInnov2); - Les_transitions_S1 transitionTo = (Les_transitions_S1) event.eval(); - stateTo = transitionTo.convertToLes_c7_covid(); - person.setLes_c7_covid(stateTo); // Use convert to les c6 covid method from the enum to convert the outcome to the les c6 scale and update the variable - - if (transitionTo.equals(Les_transitions_S1.Employee) || transitionTo.equals(Les_transitions_S1.SelfEmployed)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_S2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - - // If transition to is self-employed (i.e. continues in self-employment), and earnings have decreased (gross monthly income lower than lag1 of gross monthly income, obtained from person.getCovidModuleGrossLabourIncome_lag1), predict probabiltiy of SEISS - if (transitionTo.equals(Les_transitions_S1.SelfEmployed) && grossMonthlyIncomeToReturn < person.getCovidModuleGrossLabourIncome_lag1()) { - - double prob = Parameters.getRegC19LS_S3().getProbability(person, Person.DoublesVariables.class); - if (labourInnov3 < prob) { - // receives SEISS - - person.setCovidModuleReceivesSEISS(Indicator.True); - grossMonthlyIncomeToReturn = 0.8 * person.getCovidModuleGrossLabourIncome_lag1(); - } - } - } else if (transitionTo.equals(Les_transitions_S1.NotEmployed)) { - newWorkHours = 0; - grossMonthlyIncomeToReturn = 0; - } // No else here as new work hours and gross income are predicted if remains self-employed (above) - - // Transitions from non-employment - } else if (stateFrom.equals(Les_c7_covid.NotEmployed)) { - Map probs = Parameters.getRegC19LS_U1().getProbabilites(person, Person.DoublesVariables.class, Les_transitions_U1.class); - MultiValEvent event = new MultiValEvent(probs, labourInnov2); - Les_transitions_U1 transitionTo = (Les_transitions_U1) event.eval(); - stateTo = transitionTo.convertToLes_c7_covid(); - person.setLes_c7_covid(stateTo); // Use convert to les c6 covid method from the enum to convert the outcome to the les c6 scale and update the variable - - if (transitionTo.equals(Les_transitions_U1.Employee) || transitionTo.equals(Les_transitions_U1.SelfEmployed)) { - newWorkHours = (Labour.convertHoursToLabour(exponentiateAndConstrainWorkHoursPrediction(Parameters.getRegC19LS_U2a().getScore(person, Person.DoublesVariables.class)))).getHours(person); - grossMonthlyIncomeToReturn = Parameters.WEEKS_PER_MONTH * person.getEarningsWeekly(newWorkHours) + Math.sinh(person.getYptciihs_dv()); - } else if (transitionTo.equals(Les_transitions_U1.NotEmployed)) { - newWorkHours = 0; - grossMonthlyIncomeToReturn = 0; - } - - } else { - // System.out.println("Warning: Person " + person.getKey().getId() + " entered Covid-19 transitions process, but doesn't have correct starting labour market state which was " + stateFrom); - } - - Triple stateGrossIncomeWorkHoursTriple = Triple.of(stateTo, grossMonthlyIncomeToReturn, newWorkHours); // Triple contains outcome labour market state after transition, gross income, and work hours - person.setCovidModuleGrossLabourIncome_lag1(grossMonthlyIncomeToReturn); // used as a regressor in the Covid-19 regressions - person.setNewWorkHours_lag1(newWorkHours); // newWorkHours is not a state variable of a person and is only used from month to month in the covid module, so set lag here - person.setLes_c7_covid_lag1(stateTo); // Update lagged value of monthly labour market state - return stateGrossIncomeWorkHoursTriple; - } - private double exponentiateAndConstrainWorkHoursPrediction(double workHours) { double workHoursConverted = Math.exp(workHours); if (workHoursConverted < 0) { @@ -910,14 +747,14 @@ protected void updateLabourSupplyAndIncome() { } if (male != null) { - male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM)); + male.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekM, Gender.Male)); hoursWorkedPerWeekM = male.getLabourSupplyHoursWeekly(); labourIncomeWeeklyM = male.getEarningsWeekly(hoursWorkedPerWeekM); dlltsdM = male.getDisability(); } if (female != null) { - female.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF)); + female.setLabourSupplyWeekly(Labour.convertHoursToLabour(hoursWorkedPerWeekF, Gender.Female)); hoursWorkedPerWeekF = female.getLabourSupplyHoursWeekly(); labourIncomeWeeklyF = female.getEarningsWeekly(hoursWorkedPerWeekF); dlltsdF = female.getDisability(); @@ -988,9 +825,10 @@ protected void updateLabourSupplyAndIncome() { } else if (female.atRiskOfWork() && !male.atRiskOfWork()) { //Male not at risk of work - female must be at risk of work since only benefitUnits at risk are considered here //Follow utility process for single female regressionScore = Parameters.getRegLabourSupplyUtilityFemalesWithDependent().getScore(this, BenefitUnit.Regressors.class); - } else throw new IllegalArgumentException("None of the partners are at risk of work! HHID " + getKey().getId()); + } else if (!model.isAlignEmployment()) throw new IllegalArgumentException("None of the partners are at risk of work! HHID " + getKey().getId()); if (Double.isNaN(regressionScore) || Double.isInfinite(regressionScore)) { - throw new RuntimeException("problem evaluating exponential regression score in labour supply module (1)"); + // throw new RuntimeException("problem evaluating exponential regression score in labour supply module (1)"); + regressionScore = 0; } disposableIncomeMonthlyByLabourPairs.put(labourKey, getDisposableIncomeMonthly()); @@ -1021,7 +859,8 @@ protected void updateLabourSupplyAndIncome() { regressionScore = Parameters.getRegLabourSupplyUtilityMales().getScore(this, Regressors.class); } if (Double.isNaN(regressionScore) || Double.isInfinite(regressionScore)) { - throw new RuntimeException("problem evaluating exponential regression score in labour supply module (2)"); + // throw new RuntimeException("problem evaluating exponential regression score in labour supply module (2)"); + regressionScore = 0; } disposableIncomeMonthlyByLabourPairs.put(labourKey, getDisposableIncomeMonthly()); @@ -1049,7 +888,8 @@ protected void updateLabourSupplyAndIncome() { regressionScore = Parameters.getRegLabourSupplyUtilityFemales().getScore(this, BenefitUnit.Regressors.class); } if (Double.isNaN(regressionScore) || Double.isInfinite(regressionScore)) { - throw new RuntimeException("problem evaluating exponential regression score in labour supply module (3)"); + // throw new RuntimeException("problem evaluating exponential regression score in labour supply module (3)"); + regressionScore = 0; } disposableIncomeMonthlyByLabourPairs.put(labourKey, getDisposableIncomeMonthly()); benefitsReceivedMonthlyByLabourPairs.put(labourKey, getBenefitsReceivedPerMonth()); @@ -1359,9 +1199,11 @@ public enum Regressors { MaleLeisure_DChildren2Under, MaleLeisure_MaleDeh_c3_Low, MaleLeisure_MaleDeh_c3_Medium, - MaleLeisure_UKC, - MaleLeisure_UKD, - MaleLeisure_UKE, + MaleLeisure_PL2, + MaleLeisure_PL4, + MaleLeisure_PL5, + MaleLeisure_PL6, + MaleLeisure_PL10, MaleLeisure_UKF, MaleLeisure_UKG, MaleLeisure_UKH, @@ -1381,9 +1223,11 @@ public enum Regressors { FemaleLeisure_DChildren2Under, FemaleLeisure_FemaleDeh_c3_Low, FemaleLeisure_FemaleDeh_c3_Medium, - FemaleLeisure_UKC, - FemaleLeisure_UKD, - FemaleLeisure_UKE, + FemaleLeisure_PL2, + FemaleLeisure_PL4, + FemaleLeisure_PL5, + FemaleLeisure_PL6, + FemaleLeisure_PL10, FemaleLeisure_UKF, FemaleLeisure_UKG, FemaleLeisure_UKH, @@ -1430,76 +1274,167 @@ public enum Regressors { IncomeDiv100_MaleAgeSqDiv10000, IncomeDiv100_dnc, IncomeDiv100_dnc02, - L1_lhw_1, - L1_lhw_10, - L1_lhw_2, - L1_lhw_20, - L1_lhw_3, - L1_lhw_30, - L1_lhw_4, - L1_lhw_40, - L1_lhw_Male_1, - L1_lhw_Female_1, - L1_lhw_Male_2, - L1_lhw_Female_2, - L1_lhw_Male_3, - L1_lhw_Female_3, - L1_lhw_Male_4, - L1_lhw_Female_4, - L1_lhw_Male_10, - L1_lhw_Female_10, - L1_lhw_Male_11, - L1_lhw_Female_11, - L1_lhw_Male_12, - L1_lhw_Female_12, - L1_lhw_Male_13, - L1_lhw_Female_13, - L1_lhw_Male_14, - L1_lhw_Female_14, - L1_lhw_Male_20, - L1_lhw_Female_20, - L1_lhw_Male_21, - L1_lhw_Female_21, - L1_lhw_Male_22, - L1_lhw_Female_22, - L1_lhw_Male_23, - L1_lhw_Female_23, - L1_lhw_Male_24, - L1_lhw_Female_24, - L1_lhw_Male_30, - L1_lhw_Female_30, - L1_lhw_Male_31, - L1_lhw_Female_31, - L1_lhw_Male_32, - L1_lhw_Female_32, - L1_lhw_Male_33, - L1_lhw_Female_33, - L1_lhw_Male_34, - L1_lhw_Female_34, - L1_lhw_Male_40, - L1_lhw_Female_40, - L1_lhw_Male_41, - L1_lhw_Female_41, - L1_lhw_Male_42, - L1_lhw_Female_42, - L1_lhw_Male_43, - L1_lhw_Female_43, - L1_lhw_Male_44, - L1_lhw_Female_44, - MaleEduM_10, - MaleEduH_10, - MaleEduM_20, - MaleEduH_20, - MaleEduM_30, - MaleEduH_30, - MaleEduM_40, - MaleEduH_40, + Region2_10, + Region3_10, + Region2_20, + Region3_20, + Region2_30, + Region3_30, + Region2_1, + Region3_1, + Region2_2, + Region3_2, + Region2_3, + Region3_3, + Liwwh_1, + LiwwhSq_1, + Liwwh_10, + LiwwhSq_10, + Liwwh_2, + LiwwhSq_2, + Liwwh_20, + LiwwhSq_20, + Liwwh_3, + LiwwhSq_3, + Liwwh_30, + LiwwhSq_30, + Liwwh_Male_1, + LiwwhSq_Male_1, + Liwwh_Female_1, + LiwwhSq_Female_1, + Liwwh_Male_2, + LiwwhSq_Male_2, + Liwwh_Female_2, + LiwwhSq_Female_2, + Liwwh_Male_3, + LiwwhSq_Male_3, + Liwwh_Female_3, + LiwwhSq_Female_3, + Liwwh_Female_4, + LiwwhSq_Female_4, + Liwwh_Male_10, + LiwwhSq_Male_10, + Liwwh_Female_10, + LiwwhSq_Female_10, + Liwwh_Male_11, + LiwwhSq_Male_11, + Liwwh_Female_11, + LiwwhSq_Female_11, + Liwwh_Male_12, + LiwwhSq_Male_12, + Liwwh_Female_12, + LiwwhSq_Female_12, + Liwwh_Male_13, + LiwwhSq_Male_13, + Liwwh_Female_13, + LiwwhSq_Female_13, + Liwwh_Male_20, + LiwwhSq_Male_20, + Liwwh_Female_20, + LiwwhSq_Female_20, + Liwwh_Male_21, + LiwwhSq_Male_21, + Liwwh_Female_21, + LiwwhSq_Female_21, + Liwwh_Male_22, + LiwwhSq_Male_22, + Liwwh_Female_22, + LiwwhSq_Female_22, + Liwwh_Male_23, + LiwwhSq_Male_23, + Liwwh_Female_23, + LiwwhSq_Female_23, + Liwwh_Male_30, + LiwwhSq_Male_30, + Liwwh_Male_40, + LiwwhSq_Male_40, + Liwwh_Female_30, + LiwwhSq_Female_30, + Liwwh_Male_31, + LiwwhSq_Male_31, + Liwwh_Female_31, + LiwwhSq_Female_31, + Liwwh_Male_32, + LiwwhSq_Male_32, + Liwwh_Female_32, + LiwwhSq_Female_32, + Liwwh_Male_33, + LiwwhSq_Male_33, + Liwwh_Female_33, + LiwwhSq_Female_33, + MaleEduM_1, + MaleEduH_1, + MaleEduM_2, + MaleEduH_2, + MaleEduM_3, + MaleEduH_3, + MaleEduM_4, + MaleEduH_4, + FemaleEduM_1, + FemaleEduH_1, + FemaleEduM_2, + FemaleEduH_2, + FemaleEduM_3, + FemaleEduH_3, + FemaleEduM_4, + FemaleEduH_4, + Hrs_40plus_Male, + Hrs_40plus_Female, MaleLeisure_dnc, FemaleLeisure_dnc, MaleLeisure_dnc02, FemaleLeisure_dnc02, IncomeDiv100_FemaleAgeDiv100, IncomeDiv100_FemaleAgeSqDiv10000, + North_1, + South_Islands_1, + North_2, + South_Islands_2, + North_3, + South_Islands_3, + North_4, + South_Islands_4, + North_10, + South_Islands_10, + North_11, + South_Islands_11, + North_12, + South_Islands_12, + North_13, + South_Islands_13, + North_14, + South_Islands_14, + North_20, + South_Islands_20, + North_21, + South_Islands_21, + North_22, + South_Islands_22, + North_23, + South_Islands_23, + North_24, + South_Islands_24, + North_30, + South_Islands_30, + North_31, + South_Islands_31, + North_32, + South_Islands_32, + North_33, + South_Islands_33, + North_34, + South_Islands_34, + North_40, + South_Islands_40, + North_41, + South_Islands_41, + North_42, + South_Islands_42, + North_43, + South_Islands_43, + North_44, + South_Islands_44, + //Other Homeownership_D, // Indicator: does the benefit unit own home? @@ -1690,83 +1625,6 @@ public double getDoubleValue(Enum variableID) { return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); } else return 0.; } - case MaleLeisure_UKC -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKC)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKD -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKD)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKE -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKE)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKF -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKF)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKG -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKG)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKH -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKH)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKJ -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKJ)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKK -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKK)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKL -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKL)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKM -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKM)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case MaleLeisure_UKN -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKN)) { - return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } case MaleLeisure_MaleAge50Above -> { if (getMale().getDag() >= 50) { return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()); @@ -1806,83 +1664,6 @@ public double getDoubleValue(Enum variableID) { return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); } else return 0.; } - case FemaleLeisure_UKC -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKC)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKD -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKD)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKE -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKE)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKF -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKF)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKG -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKG)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKH -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKH)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKJ -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKJ)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKK -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKK)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKL -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKL)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKM -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKM)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } - case FemaleLeisure_UKN -> { - if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKN)) { - return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); - } else return 0.; - } else throw new IllegalArgumentException("Error - the region used in regression doesn't match the country in the simulation!"); - } case FemaleLeisure_FemaleAge50Above -> { if (getFemale().getDag() >= 50) { return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()); @@ -2076,18 +1857,7 @@ public double getDoubleValue(Enum variableID) { case HoursMaleByDelderly -> { //Appears only in Single Males regression, not Couple. return 0.; //Our model doesn't take account of elderly (as people move out of parental home when 18 years old, and we do not provide a mechanism for parents to move back in. } - case HoursMaleByDregion -> { - if(model.getCountry().equals(Country.IT)) { - if(getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG)) { //For South Italy (Sud) and Islands (Isole) - return getMale().getLabourSupplyHoursWeekly(); - } else return 0.; - } else if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKI)) { //For London - return getMale().getLabourSupplyHoursWeekly(); - } else return 0.; - } else throw new IllegalArgumentException("Error - household " + this.getId() + " has region " + getRegion() + " which is not yet handled in DonorHousehold.getDoubleValue()!"); - } case HoursFemale -> { return getFemale().getLabourSupplyHoursWeekly(); } @@ -2112,21 +1882,10 @@ public double getDoubleValue(Enum variableID) { case HoursFemaleByDelderly -> { return 0.; //Our model doesn't take account of elderly (as people move out of parental home when 18 years old, and we do not provide a mechanism for parents to move back in. } - case HoursFemaleByDregion -> { //Value of hours are already taken into account by multiplying regression coefficients in Parameters class - if(model.getCountry().equals(Country.IT)) { - if(getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG)) { //For South Italy (Sud) and Islands (Isole) - return getFemale().getLabourSupplyHoursWeekly(); - } else return 0.; - } else if(model.getCountry().equals(Country.UK)) { - if(getRegion().equals(Region.UKI)) { //For London - return getFemale().getLabourSupplyHoursWeekly(); - } else return 0.; - } else throw new IllegalArgumentException("Error - household " + this.getKey().getId() + " has region " + getRegion() + " which is not yet handled in DonorHousehold.getDoubleValue()!"); - //The following regressors for FixedCosts appear as negative in the Utility regression, and so are multiplied by a factor of -1 below. - //The following regressors only apply when the male hours worked is greater than 0 + //The following regressors for FixedCosts appear as negative in the Utility regression, and so are multiplied by a factor of -1 below. + //The following regressors only apply when the male hours worked is greater than 0 - } case FixedCostMaleByNumberChildren -> { if(getMale().getLabourSupplyHoursWeekly() > 0) { return - getNumberChildrenAll(); //Return negative as costs appear negative in utility function equation @@ -2187,199 +1946,325 @@ public double getDoubleValue(Enum variableID) { return (getDisposableIncomeMonthlyUpratedToBasePriceYear() - getNonDiscretionaryExpenditureMonthlyUpratedToBasePriceYear()) * getIndicatorChildren(0,1).ordinal() * 1.e-2; } - case L1_lhw_1 -> { + case Region2_10 -> { + return (getMale() != null && Labour.CATEGORY_1.equals(getMale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_10 -> { + return (getMale() != null && Labour.CATEGORY_1.equals(getMale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Region2_20 -> { + return (getMale() != null && Labour.CATEGORY_2.equals(getMale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_20 -> { + return (getMale() != null && Labour.CATEGORY_2.equals(getMale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Region2_30 -> { + return (getMale() != null && Labour.CATEGORY_3.equals(getMale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_30 -> { + return (getMale() != null && Labour.CATEGORY_3.equals(getMale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Region2_1 -> { + return (getFemale() != null && Labour.CATEGORY_1.equals(getFemale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_1 -> { + return (getFemale() != null && Labour.CATEGORY_1.equals(getFemale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Region2_2 -> { + return (getFemale() != null && Labour.CATEGORY_2.equals(getFemale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_2 -> { + return (getFemale() != null && Labour.CATEGORY_2.equals(getFemale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Region2_3 -> { + return (getFemale() != null && Labour.CATEGORY_3.equals(getFemale().getLabourSupplyWeekly()) && Region.HUA.equals(getRegion())) ? 1. : 0.; + } + case Region3_3 -> { + return (getFemale() != null && Labour.CATEGORY_3.equals(getFemale().getLabourSupplyWeekly()) && Region.HUB.equals(getRegion())) ? 1. : 0.; + } + case Liwwh_1 -> { // Coefficient to be applied to lagged hours of work of female member of BU interacted with "alternative 1" of hours of labour supply // Note: labour supply value for person under evaluation is set to the alternative being considered in the update labour supply process - return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_1 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_10 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_10 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_2 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_2 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_20 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_20 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_3 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_3 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_30 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_30 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_Male_1 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_Male_1 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_Female_1 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_Female_1 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_Male_2 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_Male_2 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_Female_2 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_Female_2 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_Male_3 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getMale().getLiwwh() : 0.; + } + case LiwwhSq_Male_3 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; + } + case Liwwh_Female_3 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_Female_3 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; + } + case Liwwh_Female_4 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? getFemale().getLiwwh() : 0.; + } + case LiwwhSq_Female_4 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_10 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_10 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_2 -> { - return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_10 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_20 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_10 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_3 -> { - return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_10 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_30 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_11 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_4 -> { - return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_11 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_40 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_11 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_1 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_11 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_1 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_12 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_2 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_12 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_2 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_12 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_3 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_12 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_3 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_13 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_4 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_13 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_4 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.ZERO) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_13 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_10 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_13 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_10 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_20 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_11 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_20 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_11 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_20 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_12 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_20 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_12 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_21 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_13 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_21 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_13 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_21 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_14 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_21 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_14 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_22 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_20 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_22 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_20 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_22 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_21 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_22 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_21 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_23 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_22 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_23 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_22 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_23 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_23 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_23 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_23 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_30 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_24 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_30 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_24 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_40 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_30 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_40 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_30 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_30 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_31 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_30 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_31 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_31 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_32 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_31 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_32 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_31 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_33 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_31 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_33 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_32 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_34 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_32 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_34 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_32 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_40 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_32 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_40 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Male_33 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getMale().getLiwwh() : 0.; } - case L1_lhw_Male_41 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Male_33 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getMale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_41 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TEN)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case Liwwh_Female_33 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? getFemale().getLiwwh() : 0.; } - case L1_lhw_Male_42 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case LiwwhSq_Female_33 -> { + return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? Math.pow(getFemale().getLiwwh(), 2) : 0.; } - case L1_lhw_Female_42 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.TWENTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case MaleEduM_1 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case L1_lhw_Male_43 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case MaleEduH_1 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case L1_lhw_Female_43 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.THIRTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case MaleEduM_2 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case L1_lhw_Male_44 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getMale().getL1LabourSupplyHoursWeekly() : 0.; + case MaleEduH_2 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case L1_lhw_Female_44 -> { - return (getMale() != null && getFemale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getFemale().getLabourSupplyWeekly().equals(Labour.FORTY)) ? getFemale().getL1LabourSupplyHoursWeekly() : 0.; + case MaleEduM_3 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case MaleEduM_10 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + case MaleEduH_3 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case MaleEduH_10 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TEN) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + case MaleEduM_4 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case MaleEduM_20 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + case MaleEduH_4 -> { + return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case MaleEduH_20 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.TWENTY) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + case FemaleEduM_1 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case MaleEduM_30 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + case FemaleEduH_1 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1) && getFemale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case MaleEduH_30 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.THIRTY) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + case FemaleEduM_2 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; } - case MaleEduM_40 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getMale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + case FemaleEduH_2 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2) && getFemale().getDeh_c3().equals(Education.High)) ? 1. : 0.; } - case MaleEduH_40 -> { - return (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.FORTY) && getMale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + case FemaleEduM_3 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + } + case FemaleEduH_3 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) && getFemale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + } + case FemaleEduM_4 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getFemale().getDeh_c3().equals(Education.Medium)) ? 1. : 0.; + } + case FemaleEduH_4 -> { + return (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4) && getFemale().getDeh_c3().equals(Education.High)) ? 1. : 0.; + } + case Hrs_40plus_Male -> { + return (getMale() != null && (getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3) || getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4))) ? 1. :0.; + } + case Hrs_40plus_Female -> { + return (getFemale() != null && (getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4))) ? 1. :0.; } case MaleLeisure_dnc02 -> { return (Parameters.HOURS_IN_WEEK - getMale().getLabourSupplyHoursWeekly()) * getIndicatorChildren(0,1).ordinal(); @@ -2388,6 +2273,263 @@ public double getDoubleValue(Enum variableID) { return (Parameters.HOURS_IN_WEEK - getFemale().getLabourSupplyHoursWeekly()) * getIndicatorChildren(0,1).ordinal(); } + + + case North_1 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case South_Islands_1 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + + case North_2 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + case South_Islands_2 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + + case North_3 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case South_Islands_3 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + + case North_4 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case South_Islands_4 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + + + case North_10 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + case South_Islands_10 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + + case North_11 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case South_Islands_11 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case North_12 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + case South_Islands_12 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + + case North_13 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case South_Islands_13 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + + case North_14 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case South_Islands_14 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + + case North_20 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + case South_Islands_20 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + + case North_21 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case South_Islands_21 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + + case North_22 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + case South_Islands_22 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + + case North_23 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case South_Islands_23 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + + case North_24 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case South_Islands_24 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + + case North_30 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + case South_Islands_30 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + + case North_31 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case South_Islands_31 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + + case North_32 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + case South_Islands_32 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + + case North_33 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case South_Islands_33 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + + case North_34 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case South_Islands_34 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case North_40 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + case South_Islands_40 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.ZERO)) ? 1 : 0; + } + case North_41 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + case South_Islands_41 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_1)) ? 1 : 0; + } + + case North_42 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + case South_Islands_42 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_2)) ? 1 : 0; + } + + case North_43 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case South_Islands_43 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_3)) ? 1 : 0; + } + case North_44 -> { + return (getRegion() != null && (getRegion().equals(Region.ITC) || getRegion().equals(Region.ITH))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + case South_Islands_44 -> { + return (getRegion() != null && (getRegion().equals(Region.ITF) || getRegion().equals(Region.ITG))) && + (getMale() != null && getMale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) && + (getFemale() != null && getFemale().getLabourSupplyWeekly().equals(Labour.CATEGORY_4)) ? 1 : 0; + } + + + case Homeownership_D -> { return isDhhOwned()? 1. : 0.; } @@ -3022,6 +3164,18 @@ public void setDhhOwned(boolean dhh_owned) { this.dhhOwned = dhh_owned; } + public Boolean isDhhOwned_lag1() { + if (dhhOwned_lag1 == null) { + dhhOwned_lag1 = false; + } + return dhhOwned_lag1; + } + + public void setDhhOwned_lag1(Boolean dhhOwned_lag1) { + this.dhhOwned_lag1 = dhhOwned_lag1; + } + + public ArrayList> getCovid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale() { return covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale; } diff --git a/src/main/java/simpaths/model/DisabilityAlignment.java b/src/main/java/simpaths/model/DisabilityAlignment.java new file mode 100644 index 000000000..f615921bc --- /dev/null +++ b/src/main/java/simpaths/model/DisabilityAlignment.java @@ -0,0 +1,79 @@ +package simpaths.model; + +import microsim.engine.SimulationEngine; +import simpaths.data.IEvaluation; +import simpaths.data.Parameters; +import simpaths.model.enums.Indicator; +import simpaths.model.enums.Les_c4; +import simpaths.model.enums.TargetShares; + +import java.util.Set; + + +/** + * DisabilityAlignment adjusts the probability of becoming disabled. + * The object is designed to assist modification of the intercept of the "H2b" disability model. + * + * A search routine is used to find the value by which the intercept should be adjusted. + * If the projected share of disabled individuals in the population differs from the desired target by more than a specified threshold, + * then the intercept is adjusted and the share re-evaluated. + * + * Importantly, the adjustment needs to be only found once. Modified intercepts can then be used in subsequent simulations. + */ +public class DisabilityAlignment implements IEvaluation { + + private double targetDisabledShare; + private Set persons; + private SimPathsModel model; + + + // CONSTRUCTOR + public DisabilityAlignment(Set persons) { + this.model = (SimPathsModel) SimulationEngine.getInstance().getManager(SimPathsModel.class.getCanonicalName()); + this.persons = persons; + targetDisabledShare = Parameters.getTargetShare(model.getYear(), TargetShares.Disability); + } + + + /** + * Evaluates the discrepancy between the simulated and target total retired share and adjusts probabilities if necessary. + * + * This method focuses on the influence of the adjustment parameter 'args[0]' on the difference between the target and + * simulated retired share (error). + * + * The error value is returned and serves as the stopping condition in root search routines. + * + * @param args An array of parameters, where args[0] represents the adjustment parameter. + * @return The error in the target aggregate share of retired persons after potential adjustments. + */ + @Override + public double evaluate(double[] args) { + + persons.parallelStream() + .forEach(person -> person.disability(args[0])); + + return targetDisabledShare - evalDisabledShare(); + } + + + /** + * Evaluates the aggregate share of persons with partners assigned in a test run of union matching among those eligible for partnership. + * + * This method uses Java streams to count the number of persons who meet the age criteria for cohabitation + * and the number of persons who currently have a test partner. The aggregate share is calculated as the + * ratio of successfully partnered persons to those eligible for partnership, with consideration for potential division by zero. + * + * @return The aggregate share of partnered persons among those eligible, or 0.0 if no eligible persons are found. + */ + private double evalDisabledShare() { + + long numDisabledPersons = model.getPersons().stream() + .filter(person -> (Indicator.True.equals(person.getDlltsd()))) + .count(); + long numPeople = model.getPersons().stream() + .filter(person -> person.getDlltsd() != null) + .count(); + + return (numDisabledPersons > 0) ? (double) numDisabledPersons / numPeople : 0.0; + } +} diff --git a/src/main/java/simpaths/model/FertilityAlignment.java b/src/main/java/simpaths/model/FertilityAlignment.java index 77297887f..66e336df7 100644 --- a/src/main/java/simpaths/model/FertilityAlignment.java +++ b/src/main/java/simpaths/model/FertilityAlignment.java @@ -4,8 +4,6 @@ import simpaths.data.IEvaluation; import simpaths.data.Parameters; import simpaths.data.filters.FertileFilter; -import simpaths.model.enums.Dcpst; -import simpaths.model.enums.TimeSeriesVariable; import java.util.Set; @@ -49,9 +47,8 @@ public FertilityAlignment(Set persons) { @Override public double evaluate(double[] args) { - double newAlignAdjustment = args[0] + Parameters.getTimeSeriesValue(model.getYear(), TimeSeriesVariable.FertilityAdjustment); persons.parallelStream() - .forEach(person -> person.fertility(newAlignAdjustment)); + .forEach(person -> person.fertility(args[0])); return targetFertilityRate - evalFertilityRate(); } diff --git a/src/main/java/simpaths/model/InSchoolAlignment.java b/src/main/java/simpaths/model/InSchoolAlignment.java new file mode 100644 index 000000000..803596edf --- /dev/null +++ b/src/main/java/simpaths/model/InSchoolAlignment.java @@ -0,0 +1,76 @@ +package simpaths.model; + +import microsim.engine.SimulationEngine; +import simpaths.data.IEvaluation; +import simpaths.data.Parameters; +import simpaths.model.enums.Les_c4; +import simpaths.model.enums.TargetShares; + +import java.util.Set; + + +/** + * InSchoolAlignment adjusts the probability of being a student. + * The object is designed to assist modification of the intercept of the "inSchool" models. + * + * A search routine is used to find the value by which the intercept should be adjusted. + * If the projected share of students in the population differs from the desired target by more than a specified threshold, + * then the intercept is adjusted and the share re-evaluated. + * + * Importantly, the adjustment needs to be only found once. Modified intercepts can then be used in subsequent simulations. + */ +public class InSchoolAlignment implements IEvaluation { + + private double targetStudentShare; + private Set persons; + private SimPathsModel model; + + + // CONSTRUCTOR + public InSchoolAlignment(Set persons) { + this.model = (SimPathsModel) SimulationEngine.getInstance().getManager(SimPathsModel.class.getCanonicalName()); + this.persons = persons; + targetStudentShare = Parameters.getTargetShare(model.getYear(), TargetShares.Students); + } + + + /** + * Evaluates the discrepancy between the simulated and target total student share and adjusts probabilities if necessary. + * + * This method focuses on the influence of the adjustment parameter 'args[0]' on the difference between the target and + * simulated student share (error). + * + * The error value is returned and serves as the stopping condition in root search routines. + * + * @param args An array of parameters, where args[0] represents the adjustment parameter. + * @return The error in the target aggregate share of students after potential adjustments. + */ + @Override + public double evaluate(double[] args) { + + persons.parallelStream() + .forEach(person -> person.inSchool(args[0])); + + return targetStudentShare - evalStudentShare(); + } + + + /** + * Evaluates the aggregate share of students. + * + * This method uses Java streams to count the number of students over the total number of individuals. + * + * @return The aggregate share of partnered persons among those eligible, or 0.0 if no eligible persons are found. + */ + private double evalStudentShare() { + + long numStudents = model.getPersons().stream() + .filter(person -> (!person.isToLeaveSchool() && !Les_c4.EmployedOrSelfEmployed.equals(person.getLes_c4()) && !Les_c4.NotEmployed.equals(person.getLes_c4()) && !Les_c4.Retired.equals(person.getLes_c4()))) // count number of students who are not supposed to leave school + .count(); + long numPeople = model.getPersons().stream() + .filter(person -> person.getLes_c4() != null) + .count(); + + return (numStudents > 0) ? (double) numStudents / numPeople : 0.0; + } +} diff --git a/src/main/java/simpaths/model/LabourMarket.java b/src/main/java/simpaths/model/LabourMarket.java index 0d74e06bc..f64b91a71 100644 --- a/src/main/java/simpaths/model/LabourMarket.java +++ b/src/main/java/simpaths/model/LabourMarket.java @@ -1,41 +1,28 @@ package simpaths.model; +import microsim.engine.SimulationEngine; +import simpaths.data.Parameters; +import simpaths.model.enums.Education; +import simpaths.model.enums.MacroScenarioPopulation; +import simpaths.model.enums.Region; + import java.util.*; import java.util.random.RandomGenerator; -import simpaths.data.statistics.Statistics; -import simpaths.experiment.SimPathsCollector; -import simpaths.model.enums.*; - -import simpaths.data.Parameters; -//import experiment.SimPathsObserver; -//import microsim.data.MultiKeyCoefficientMap; -import microsim.engine.SimulationEngine; -//import microsim.statistics.IDoubleSource; -//import microsim.statistics.ILongSource; - //Significantly simplified LabourMarket module. Should just contain simple labour supply for now and matching with euromod donor population. public class LabourMarket { private final SimPathsModel model; -// private final SimPathsObserver observer; //Not used but maybe we want to graph labour supply and earnings etc. in the observer - private String EUROMODpolicyNameForThisYear; - private LinkedHashMap> benefitUnitsByRegion; //Don't think we care about regions, but maybe benefitUnits are matched by region? + private final LinkedHashMap> benefitUnitsByRegion; //Don't think we care about regions, but maybe benefitUnits are matched by region? - private Set benefitUnitsAllRegions; - - private Set benefitUnitsCovid19Update; - - private Map disposableIncomesByRegion; + private final Set benefitUnitsAllRegions; Set benefitUnits; - private int covid19TransitionsMonth; - RandomGenerator labourInnov; @@ -49,7 +36,6 @@ public class LabourMarket { benefitUnitsByRegion = new LinkedHashMap>(); //For use in labour market module benefitUnitsAllRegions = new LinkedHashSet<>(); - benefitUnitsCovid19Update = new LinkedHashSet<>(); for(Region region : Parameters.getCountryRegions()) { benefitUnitsByRegion.put(region, new LinkedHashSet()); @@ -61,160 +47,6 @@ public class LabourMarket { protected void update(int year) { - /* - In Covid-19 years (2020, 2021) the update method uses reduced form models, if the labourMarketCovid19On boolean is set to true in the SimPathsModel class - Need to model wages and hours of work (as the other labour supply module would do), calculate disposable income by matching with monthly EM files, and then proceed with the rest of the model - */ - - if (model.isLabourMarketCovid19On() && year >= 2020 && year <= 2021) { // If true, apply the reduced form models - - if (year == 2020) { // In 2020, start in April - setCovid19TransitionsMonth(4); - } else { // Otherwise start in January - setCovid19TransitionsMonth(1); - } - - // Clear set of benefit units to update - benefitUnitsCovid19Update.clear(); - - for (BenefitUnit benefitUnit : benefitUnits) { - benefitUnit.updateNonLabourIncome(); - if (benefitUnit.getAtRiskOfWork()) { - benefitUnitsCovid19Update.add(benefitUnit); // Put benefit units at risk of work in a set to update. Could use the same set as structural model, but seems cleaner to keep the two separate - } else { - benefitUnit.updateDisposableIncomeIfNotAtRiskOfWork(); - } - } - - for (BenefitUnit benefitUnit : benefitUnitsCovid19Update) { - - // Clear objects used in the Covid-19 module at the beginning of the year: - benefitUnit.covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleMale.clear(); // Clear ArrayList storing monthly outcomes for male member of the benefit unit (labour market states and gross incomes) - benefitUnit.covid19MonthlyStateAndGrossIncomeAndWorkHoursTripleFemale.clear(); // Clear ArrayList storing monthly outcomes for female member of the benefit unit (labour market states and gross incomes) - - // Update fields of benefit units entering Covid-19 module: - benefitUnit.resetLabourStates(); // Update potential earnings which are then used to calculate gross income in the Covid-19 module - - // TODO: At the end of the year, having saved monthly states and corresponding gross incomes, sample one at random that will be the "yearly" value. This recreates the way in which FRS data underlying EUROMOD is sampled. - /* - Prepare simulated objects when the Covid-19 module runs for the first time (first month of the first year - April 2020) - In the simulation, there is no distinction between employed and self-employed individuals. - In the first month of the first Covid-19 year, we use a new process (RegC19LS_SE) to determine which individuals, out of those in EmployedOrSelfEmployed category, are self-employed and assign that status in Les_c7_covid enum. - The code below also copies values of les_c4 to assign starting values of les_c6. - */ - - LinkedHashSet personsInBenefitUnit = new LinkedHashSet<>(); // Store adults from the benefit unit - Occupancy occupancy = benefitUnit.getOccupancy(); - if ((year == 2020 && getCovid19TransitionsMonth() == 4)) { - - if (occupancy.equals(Occupancy.Couple)) { - Person male = benefitUnit.getMale(); - Person female = benefitUnit.getFemale(); - personsInBenefitUnit.add(male); - personsInBenefitUnit.add(female); - // For male, female set initial value of les_c6 based on current value of les_c4 - male.initialise_les_c6_from_c4(); - female.initialise_les_c6_from_c4(); - - boolean setMaleSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(male, Person.DoublesVariables.class)); - boolean setFemaleSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(female, Person.DoublesVariables.class)); - if (setMaleSelfEmployed && male.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - male.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - if (setFemaleSelfEmployed && female.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - female.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } else if (occupancy.equals(Occupancy.Single_Male)) { - Person male = benefitUnit.getMale(); - male.initialise_les_c6_from_c4(); - personsInBenefitUnit.add(male); - boolean setSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(male, Person.DoublesVariables.class)); - if (setSelfEmployed && male.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - male.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } else if (occupancy.equals(Occupancy.Single_Female)) { - Person female = benefitUnit.getFemale(); - female.initialise_les_c6_from_c4(); - personsInBenefitUnit.add(female); - boolean setSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(female, Person.DoublesVariables.class)); - if (setSelfEmployed && female.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - female.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } else { - throw new RuntimeException("Warning: Occupancy unknown in benefit unit " + benefitUnit.getKey().getId()); - } - updateGrossLabourIncomeBaseline_Xt5(personsInBenefitUnit); - } - - // Households are created and destroyed each year, so there might be some in 2021 who were not in the simulation in 2020 and need to be initialised - if (year == 2021 && getCovid19TransitionsMonth() == 1) { - - if (occupancy.equals(Occupancy.Couple)) { - Person male = benefitUnit.getMale(); - Person female = benefitUnit.getFemale(); - personsInBenefitUnit.add(male); - personsInBenefitUnit.add(female); - if (male != null && male.getLes_c7_covid() == null) { - male.initialise_les_c6_from_c4(); - boolean setMaleSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(male, Person.DoublesVariables.class)); - if (setMaleSelfEmployed && male.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - male.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } - if (female != null && female.getLes_c7_covid() == null) { - female.initialise_les_c6_from_c4(); - boolean setFemaleSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(female, Person.DoublesVariables.class)); - if (setFemaleSelfEmployed && female.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - female.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } - } else if (occupancy.equals(Occupancy.Single_Male)) { - Person male = benefitUnit.getMale(); - personsInBenefitUnit.add(male); - if (male != null && male.getLes_c7_covid() == null) { - male.initialise_les_c6_from_c4(); - boolean setSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(male, Person.DoublesVariables.class)); - if (setSelfEmployed && male.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - male.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } - } else if (occupancy.equals(Occupancy.Single_Female)) { - Person female = benefitUnit.getFemale(); - personsInBenefitUnit.add(female); - if (female != null && female.getLes_c7_covid() == null) { - female.initialise_les_c6_from_c4(); - boolean setSelfEmployed = (labourInnov.nextDouble() < Parameters.getRegC19LS_SE().getProbability(female, Person.DoublesVariables.class)); - if (setSelfEmployed && female.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed)) { - female.setLes_c7_covid(Les_c7_covid.SelfEmployed); - } - } - } - updateGrossLabourIncomeBaseline_Xt5(personsInBenefitUnit); - } - } - - // Monthly Covid-19 updates below - for (int currentMonth = getCovid19TransitionsMonth(); currentMonth <= 12; currentMonth++) { - - /* - In the reduced form the transitions depend on regressions. Different regression is applied for different past states: employed, self-employed, not-employed, furloughed. - We store all monthly values, and at the end of the year choose one value at random to replicate sampling design of FRS and EUROMOD. But labour market states and incomes have to be updated from month to month first, as next month's state depends on the previous month. - updateMonthlyLabourSupplyCovid19() method predicts monthly transition, work hours, gross and disposable income and adds such triplet to an array list keeping track of monthly values. - */ - for (BenefitUnit benefitUnit : benefitUnitsCovid19Update) { - - benefitUnit.updateMonthlyLabourSupplyCovid19(); - } - incrementCovid19TransitionsMonth(1); - } - - // When all the monthly transitions in a year have been predicted, choose one monthly value to represent the whole year for each individual and set labour force status, work hours, gross and disposable income. - // benefitUnitsCovid19Update.parallelStream().forEach(benefitUnit -> benefitUnit.chooseRandomMonthlyOutcomeCovid19()); - for (BenefitUnit benefitUnit : benefitUnitsCovid19Update) { - benefitUnit.chooseRandomMonthlyOutcomeCovid19(); - } - - } else { // Otherwise, use the default model of labour supply EUROMODpolicyNameForThisYear = Parameters.getEUROMODpolicyForThisYear(year); //Update EUROMOD policy to apply to this year @@ -234,12 +66,16 @@ Need to model wages and hours of work (as the other labour supply module would d } } - if (model.isAlignEmployment() & model.getYear() <= 2019) { + if (model.isAlignEmployment() & model.getYear() <= 2035 & !model.isMacroShocksOn()) { model.activityAlignmentSingleMales(); model.activityAlignmentSingleFemales(); model.activityAlignmentCouples(); } + if (model.isMacroShocksOn()) { + model.activityAlignmentMacroShock(); + } + //Update Labour Supply benefitUnitsAllRegions.parallelStream() .forEach(BenefitUnit::updateLabourSupplyAndIncome); @@ -283,88 +119,5 @@ Need to model wages and hours of work (as the other labour supply module would d benefitUnits.stream() .forEach(BenefitUnit::updateActivityOfPersonsWithinBenefitUnit); - } - } - - - /////////////////////////////////////////////////////////////////////////////////////// - // - // Other Methods - // - /////////////////////////////////////////////////////////////////////////////////////// - - public void updateGrossLabourIncomeBaseline_Xt5(LinkedHashSet personsInBenefitUnit) { - for (Person person : personsInBenefitUnit) { - if (person != null && person.getCovidModuleGrossLabourIncomeBaseline_Xt5() == null) { - double covidModuleGrossLabourIncomeBaseline = person.getCovidModuleGrossLabourIncome_Baseline(); - Statistics stats = ((SimPathsCollector) SimulationEngine.getInstance().getManager(SimPathsCollector.class.getCanonicalName())).getStats(); - if (covidModuleGrossLabourIncomeBaseline <= stats.getGrossLabourIncome_p20()) { - person.setCovidModuleGrossLabourIncomeBaseline_Xt5(Quintiles.Q1); - } else if (covidModuleGrossLabourIncomeBaseline <= stats.getGrossLabourIncome_p40()) { - person.setCovidModuleGrossLabourIncomeBaseline_Xt5(Quintiles.Q2); - } else if (covidModuleGrossLabourIncomeBaseline <= stats.getGrossLabourIncome_p60()) { - person.setCovidModuleGrossLabourIncomeBaseline_Xt5(Quintiles.Q3); - } else if (covidModuleGrossLabourIncomeBaseline <= stats.getGrossLabourIncome_p80()) { - person.setCovidModuleGrossLabourIncomeBaseline_Xt5(Quintiles.Q4); - } else { - person.setCovidModuleGrossLabourIncomeBaseline_Xt5(Quintiles.Q5); - } - } - } - } - - public int getMonthForRegressor() { - int year = model.getYear(); - int month = getCovid19TransitionsMonth(); - int returnValue = 0; - - if (year == 2020) { - if (month == 4) { - returnValue = 1; - } else if (month == 5) { - returnValue = 2; - } else if (month == 6) { - returnValue = 3; - } else if (month == 7 || month == 8) { - returnValue = 4; - } else if (month == 9 || month == 10) { - returnValue = 5; - } else if (month == 11 || month == 12) { - returnValue = 6; - } - } else if (year == 2021) { - if (month == 1 || month == 2) { - returnValue = 7; - } else if (month == 3 || month == 4) { - returnValue = 8; - } else if (month >= 5) { - returnValue = 9; - } - } else if (year > 2021) { - returnValue = 9; //Keep month equal to 9 for dates later than the last month observed in the data - } - return returnValue; - } - - - //------------------------------------------------------------------------- - // Access Methods - //------------------------------------------------------------------------- - - - public String getEUROMODpolicyNameForThisYear() { - return EUROMODpolicyNameForThisYear; - } - - public int getCovid19TransitionsMonth() { - return covid19TransitionsMonth; - } - - public void setCovid19TransitionsMonth(int covid19TransitionsMonth) { - this.covid19TransitionsMonth = covid19TransitionsMonth; - } - - public void incrementCovid19TransitionsMonth(int increment) { - covid19TransitionsMonth = covid19TransitionsMonth+increment; } } diff --git a/src/main/java/simpaths/model/PartnershipAlignment.java b/src/main/java/simpaths/model/PartnershipAlignment.java index a99be2df3..5bcf6c30b 100644 --- a/src/main/java/simpaths/model/PartnershipAlignment.java +++ b/src/main/java/simpaths/model/PartnershipAlignment.java @@ -3,9 +3,7 @@ import microsim.engine.SimulationEngine; import simpaths.data.IEvaluation; import simpaths.data.Parameters; -import simpaths.model.enums.Dcpst; import simpaths.model.enums.TargetShares; -import simpaths.model.enums.TimeSeriesVariable; import java.util.Set; @@ -51,10 +49,9 @@ public PartnershipAlignment(Set persons) { public double evaluate(double[] args) { model.clearPersonsToMatch(); - double newAlignAdjustment = args[0] + Parameters.getTimeSeriesValue(model.getYear(), TimeSeriesVariable.PartnershipAdjustment); persons.parallelStream() .filter(person -> person.getDag() >= Parameters.MIN_AGE_COHABITATION) - .forEach(person -> person.cohabitation(newAlignAdjustment)); + .forEach(person -> person.cohabitation(args[0])); // "Fake" union matching (not modifying household structure) here model.unionMatching(true); @@ -80,6 +77,7 @@ private double evalAggregateShareOfPartneredPersons() { .count(); long numPersonsPartnered = persons.stream() + .filter(person -> person.getDag() >= Parameters.MIN_AGE_COHABITATION) .filter(person -> (person.getTestPartner() || (person.getPartner()!=null && !person.getLeavePartner() && !person.getPartner().getLeavePartner()))) diff --git a/src/main/java/simpaths/model/Person.java b/src/main/java/simpaths/model/Person.java index 63e6e774a..72354bcd5 100644 --- a/src/main/java/simpaths/model/Person.java +++ b/src/main/java/simpaths/model/Person.java @@ -1,30 +1,28 @@ package simpaths.model; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.*; - import jakarta.persistence.*; - +import microsim.agent.Weight; import microsim.data.db.PanelEntityKey; +import microsim.engine.SimulationEngine; +import microsim.event.EventListener; +import microsim.statistics.IDoubleSource; +import microsim.statistics.IIntSource; +import microsim.statistics.Series; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.log4j.Logger; import simpaths.data.ManagerRegressions; import simpaths.data.MultiValEvent; +import simpaths.data.Parameters; import simpaths.data.RegressionName; import simpaths.data.filters.FertileFilter; import simpaths.model.decisions.Axis; +import simpaths.model.decisions.DecisionParams; import simpaths.model.enums.*; -import microsim.statistics.Series; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.log4j.Logger; -import simpaths.data.Parameters; -import simpaths.model.decisions.DecisionParams; -import microsim.agent.Weight; -import microsim.engine.SimulationEngine; -import microsim.event.EventListener; -import microsim.statistics.IDoubleSource; -import microsim.statistics.IIntSource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; import static simpaths.data.Parameters.getUnemploymentRateByGenderEducationAgeYear; @@ -51,6 +49,7 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight, private Long idOriginalHH; private Long idMother; private Long idFather; + private Long idPartner; private Boolean clonedFlag; private Boolean bornInSimulation; //Flag to keep track of newborns private Long seed; @@ -61,6 +60,7 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight, // person level variables private int dag; //Age + private Dcpst dcpst; @Enumerated(EnumType.STRING) private Indicator adultchildflag; @Transient private boolean ioFlag; // true if a dummy person instantiated for IO decision solution @Enumerated(EnumType.STRING) private Gender dgn; // gender @@ -72,9 +72,9 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight, @Enumerated(EnumType.STRING) private Indicator der; // return to education @Enumerated(EnumType.STRING) private Les_c4 les_c4; //Activity (employment) status @Enumerated(EnumType.STRING) private Les_c7_covid les_c7_covid; //Activity (employment) status used in the Covid-19 models - @Transient private Les_c4 les_c4_lag1; //Lag(1) of activity_status + @Enumerated(EnumType.STRING) private Les_c4 les_c4_lag1; //Lag(1) of activity_status @Transient private Les_c7_covid les_c7_covid_lag1; //Lag(1) of 7-category activity status - @Transient private Integer liwwh; //Work history in months (number of months in employment) (Note: this is monthly in EM, but simulation updates annually so increment by 12 months). + private Integer liwwh; //Work history in years (number of years in employment) @Enumerated(EnumType.STRING) private Indicator dlltsd; //Long-term sick or disabled if = 1 @Transient private Indicator dlltsd_lag1; //Lag(1) of long-term sick or disabled @Enumerated(EnumType.STRING) @Column(name="need_socare") private Indicator needSocialCare; @@ -116,6 +116,7 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight, @Enumerated(EnumType.STRING) private Indicator sedex; // year left education @Transient private Boolean toGiveBirth; + @Transient private Boolean toRetire; @Transient private Boolean toLeaveSchool; @Transient private Boolean toBePartnered; @Transient private Boolean hasTestPartner; @@ -140,8 +141,8 @@ public class Person implements EventListener, IDoubleSource, IIntSource, Weight, // age, education, civil status, number of children, etc. Hence, potential earnings // is a separate process in the simulation, and it is computed for every adult // individual in the simulated population, in each simulated period. - @Column(name="potential_earnings_hourly") private Double fullTimeHourlyEarningsPotential; //Is hourly rate. Initialised with value: ils_earns / (4.34 * lhw), where lhw is the weekly hours a person worked in EUROMOD input data - @Column(name="l1_potential_earnings_hourly") private Double L1_fullTimeHourlyEarningsPotential; // Lag(1) of potentialHourlyEarnings + @Column(name="obs_earnings_hourly") private Double fullTimeHourlyEarningsPotential; //Is hourly rate. Initialised with value: ils_earns / (4.34 * lhw), where lhw is the weekly hours a person worked in EUROMOD input data + @Column(name="l1_obs_earnings_hourly") private Double L1_fullTimeHourlyEarningsPotential; // Lag(1) of potentialHourlyEarnings @Transient private Series.Double yearlyEquivalisedDisposableIncomeSeries; private Double yearlyEquivalisedConsumption; @Transient private Series.Double yearlyEquivalisedConsumptionSeries; @@ -381,7 +382,7 @@ else if (dag > Parameters.MAX_AGE_TO_LEAVE_CONTINUOUS_EDUCATION) ypnoab_lag1 = originalPerson.ypnoab_lag1; ypnoab_lag2 = originalPerson.ypnoab_lag2; - liwwh = Objects.requireNonNullElseGet(originalPerson.liwwh, () -> ((Les_c4.EmployedOrSelfEmployed.equals(les_c4)) ? 12 : 0)); + liwwh = Objects.requireNonNullElseGet(originalPerson.liwwh, () -> ((Les_c4.EmployedOrSelfEmployed.equals(les_c4)) ? 1 : 0)); dlltsd = originalPerson.dlltsd; dlltsd_lag1 = originalPerson.dlltsd_lag1; needSocialCare = Objects.requireNonNullElse(originalPerson.needSocialCare, Indicator.False); @@ -568,14 +569,10 @@ private void setAllSocialCareVariablesToFalse() { public void setAdditionalFieldsInInitialPopulation() { if (labourSupplyWeekly==null) - labourSupplyWeekly = Labour.convertHoursToLabour(model.getInitialHoursWorkedWeekly().get(key.getId()).intValue()); + labourSupplyWeekly = Labour.convertHoursToLabour(model.getInitialHoursWorkedWeekly().get(key.getId()).intValue(), getDgn()); receivesBenefitsFlag_L1 = receivesBenefitsFlag; labourSupplyWeekly_L1 = getLabourSupplyWeekly(); - if(UnionMatchingMethod.SBAM.equals(model.getUnionMatchingMethod())) { - updateAgeGroup(); - } - hoursWorkedWeekly = null; //Not to be updated as labourSupplyWeekly contains this information. updateVariables(true); } @@ -646,6 +643,7 @@ public enum Processes { SocialCareProvision, Unemployment, Update, + UpdateOutputVariables, UpdatePotentialHourlyEarnings, //Needed to union matching and labour supply } @@ -658,6 +656,9 @@ public void onEvent(Enum type) { case Update -> { updateVariables(false); } + case UpdateOutputVariables -> { + updateOutputVariables(); + } case ProjectEquivConsumption -> { projectEquivConsumption(); } @@ -673,6 +674,7 @@ public void onEvent(Enum type) { } case ConsiderRetirement -> { considerRetirement(); + retire(); } case Fertility -> { fertility(); @@ -684,6 +686,7 @@ public void onEvent(Enum type) { case Health -> { // log.debug("Health for person " + this.getKey().getId()); health(); + disability(); } case SocialCareReceipt -> { evaluateSocialCareReceipt(); @@ -727,7 +730,6 @@ public void onEvent(Enum type) { public void fertility() { double probitAdjustment = (model.isAlignFertility()) ? Parameters.getAlignmentValue(getYear(), AlignmentVariable.FertilityAlignment) : 0.0; - probitAdjustment += Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.FertilityAdjustment); fertility(probitAdjustment); } @@ -738,7 +740,6 @@ public void fertility(double probitAdjustment) { if (filter.evaluate(this)) { double prob; - if (model.getCountry().equals(Country.UK)) { if (getDag() <= 29 && getLes_c4().equals(Les_c4.Student) && !isLeftEducation()) { //If age below or equal to 29 and in continuous education follow process F1a @@ -749,11 +750,6 @@ public void fertility(double probitAdjustment) { double score = Parameters.getRegFertilityF1b().getScore(this, Person.DoublesVariables.class); prob = Parameters.getRegFertilityF1b().getProbability(score + probitAdjustment); } - } else if (model.getCountry().equals(Country.IT)) { - - prob = Parameters.getRegFertilityF1().getProbability(this, Person.DoublesVariables.class); - } else - throw new RuntimeException("Country not recognised when evaluating fertility status"); if (innovations.getDoubleDraw(29)= Parameters.MIN_AGE_TO_RETIRE && !Les_c4.Retired.equals(les_c4) && !Les_c4.Retired.equals(les_c4_lag1)) { if (Parameters.enableIntertemporalOptimisations && DecisionParams.flagRetirement) { if (Labour.ZERO.equals(labourSupplyWeekly_L1)) { @@ -870,18 +872,24 @@ public boolean considerRetirement() { } else { double prob; if (getPartner() != null) { - prob = Parameters.getRegRetirementR1b().getProbability(this, Person.DoublesVariables.class); + double score = Parameters.getRegRetirementR1b().getScore(this, Person.DoublesVariables.class); + prob = Parameters.getRegRetirementR1b().getProbability(score + probitAdjustment); } else { - prob = Parameters.getRegRetirementR1a().getProbability(this, Person.DoublesVariables.class); + double score = Parameters.getRegRetirementR1a().getScore(this, Person.DoublesVariables.class); + prob = Parameters.getRegRetirementR1a().getProbability(score + probitAdjustment); } toRetire = (innovations.getDoubleDraw(23) < prob); } - if (toRetire) { - setLes_c4(Les_c4.Retired); - } } return toRetire; } + + public void retire() { + if (toRetire) { + setLes_c4(Les_c4.Retired); + } + } + /* This method corresponds to Step 1 of the mental health evaluation: predict level of mental health on the GHQ-12 Likert scale based on observable characteristics @@ -958,26 +966,32 @@ protected Double constrainDhmEstimate(Double dhm) { //Health process defines health using H1a or H1b process protected void health() { - double healthInnov1 = innovations.getDoubleDraw(3); - double healthInnov2 = innovations.getDoubleDraw(4); if((dag >= 16 && dag <= 29) && Les_c4.Student.equals(les_c4) && leftEducation == false) { //If age is between 16 - 29 and individual has always been in education, follow process H1a: - - Map probs = Parameters.getRegHealthH1a().getProbabilities(this, Person.DoublesVariables.class); + Map probs = ManagerRegressions.getProbabilities(this, RegressionName.HealthH1a); MultiValEvent event = new MultiValEvent(probs, healthInnov1); dhe = (Dhe) event.eval(); } else if (dag >= 16) { - - Map probs = Parameters.getRegHealthH1b().getProbabilities(this, Person.DoublesVariables.class); + Map probs = ManagerRegressions.getProbabilities(this, RegressionName.HealthH1b); MultiValEvent event = new MultiValEvent(probs, healthInnov1); dhe = (Dhe) event.eval(); + } + } + public void disability() { + double probitAdjustment = (model.isAlignDisability()) ? Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.DisabilityAdjustment) : 0.0; + disability(probitAdjustment); + } + + protected void disability(double probitAdjustment) { + double healthInnov2 = innovations.getDoubleDraw(4); + if (dag >= 16 && (!Les_c4.Student.equals(les_c4) || (leftEducation == true))) { //If age is over 16 and individual is not in continuous education, also follow process H2b to calculate the probability of long-term sickness / disability: boolean becomeLTSickDisabled = false; if (!Parameters.enableIntertemporalOptimisations || DecisionParams.flagDisability) { - - double prob = Parameters.getRegHealthH2b().getProbability(this, Person.DoublesVariables.class); + double score = Parameters.getRegHealthH2b().getScore(this, Person.DoublesVariables.class); + double prob = Parameters.getRegHealthH2b().getProbability(score + probitAdjustment); becomeLTSickDisabled = (healthInnov2 < prob); } if (becomeLTSickDisabled) { @@ -1064,7 +1078,7 @@ protected void evaluateSocialCareReceipt() { if (recCareInnov < probRecCare) { // receive care - Map probs1 = Parameters.getRegSocialCareMarketS2c().getProbabilites(this, Person.DoublesVariables.class); + Map probs1 = Parameters.getRegSocialCareMarketS2c().getProbabilities(this, Person.DoublesVariables.class); MultiValEvent event = new MultiValEvent(probs1, innovations.getDoubleDraw(8)); SocialCareReceiptS2c socialCareReceiptS2c = (SocialCareReceiptS2c) event.eval(); socialCareReceipt = SocialCareReceipt.getCode(socialCareReceiptS2c); @@ -1083,7 +1097,7 @@ protected void evaluateSocialCareReceipt() { socialCareFromPartner = true; Map probs2 = - Parameters.getRegPartnerSupplementaryCareS2e().getProbabilites(this, Person.DoublesVariables.class); + Parameters.getRegPartnerSupplementaryCareS2e().getProbabilities(this, Person.DoublesVariables.class); event = new MultiValEvent(probs2, innovations.getDoubleDraw(10)); PartnerSupplementaryCarer cc = (PartnerSupplementaryCarer) event.eval(); if (PartnerSupplementaryCarer.Daughter.equals(cc)) @@ -1098,7 +1112,7 @@ protected void evaluateSocialCareReceipt() { // no care from partner - identify who supplies informal care Map probs2 = - Parameters.getRegNotPartnerInformalCareS2f().getProbabilites(this, Person.DoublesVariables.class); + Parameters.getRegNotPartnerInformalCareS2f().getProbabilities(this, Person.DoublesVariables.class); event = new MultiValEvent(probs2, innovations.getDoubleDraw(11)); NotPartnerInformalCarer cc = (NotPartnerInformalCarer) event.eval(); if (NotPartnerInformalCarer.DaughterOnly.equals(cc) || NotPartnerInformalCarer.DaughterAndSon.equals(cc) || NotPartnerInformalCarer.DaughterAndOther.equals(cc)) @@ -1210,7 +1224,6 @@ public void evaluateSocialCareProvision(double probitAdjustment) { public void cohabitation() { double probitAdjustment = (model.isAlignCohabitation()) ? Parameters.getAlignmentValue(getYear(), AlignmentVariable.PartnershipAlignment) : 0.0; - probitAdjustment += Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.PartnershipAdjustment); cohabitation(probitAdjustment); } @@ -1228,8 +1241,6 @@ protected void cohabitation(double probitAdjustment) { if (dag >= Parameters.MIN_AGE_COHABITATION) { // cohabitation possible - if (model.getCountry() == Country.UK) { - double prob; if (partner == null) { // partnership formation @@ -1255,24 +1266,7 @@ protected void cohabitation(double probitAdjustment) { leavePartner = true; } } - } else if (model.getCountry() == Country.IT) { - - if (partner == null) { - if ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student)) { - - double prob = Parameters.getRegPartnershipITU1().getProbability(this, Person.DoublesVariables.class); - toBePartnered = (cohabitInnov < prob); - if (toBePartnered) - model.getPersonsToMatch().get(dgn).get(getRegion()).add(this); - } - } else if (partner != null && dgn == Gender.Female && ((les_c4 == Les_c4.Student && leftEducation) || !les_c4.equals(Les_c4.Student))) { - double prob = Parameters.getRegPartnershipITU2().getProbability(this, Person.DoublesVariables.class); - if (cohabitInnov < prob) { - leavePartner = true; - } - } - } } } @@ -1293,49 +1287,79 @@ protected void partnershipDissolution() { } } - protected void inSchool() { + public boolean inSchool() { + double probitAdjustment = (model.isAlignInSchool()) ? Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.InSchoolAdjustment) : 0.0; + return inSchool(probitAdjustment); + } + + + protected boolean inSchool(double probitAdjustment) { + // IMPORTANT ensure each "if" returns true/false or toLeaveSchool value + // Innovation for education decisions double labourInnov = innovations.getDoubleDraw(24); - //Min age to leave education set to 16 (from 18 previously) but note that age to leave home is 18. - if (Les_c4.Retired.equals(les_c4) || dag < Parameters.MIN_AGE_TO_LEAVE_EDUCATION || dag > Parameters.MAX_AGE_TO_ENTER_EDUCATION) { //Only apply module for persons who are old enough to consider leaving education, but not retired - return; - } else if (Les_c4.Student.equals(les_c4) && !leftEducation && dag >= Parameters.MIN_AGE_TO_LEAVE_EDUCATION) { //leftEducation is initialised to false and updated to true when individual leaves education (and never reset). - //If age is between 16 - 29 and individual has always been in education, follow process E1a: - if (dag <= Parameters.MAX_AGE_TO_LEAVE_CONTINUOUS_EDUCATION) { + // Check if the individual is eligible for education transitions + if (Les_c4.Retired.equals(les_c4) || + dag < Parameters.MIN_AGE_TO_LEAVE_EDUCATION) { + return false; //inSchool stops here; Case 1 and Case 2 are not considered + } - double prob = Parameters.getRegEducationE1a().getProbability(this, Person.DoublesVariables.class); - toLeaveSchool = (labourInnov >= prob); //If event is true, stay in school. If event is false, leave school. - } else { - toLeaveSchool = true; //Hasn't left education until 30 - force out - } - } else if (dag <= 45 && (!Les_c4.Student.equals(les_c4) || leftEducation)) { //leftEducation is initialised to false and updated to true when individual leaves education for the first time (and never reset). - //If age is between 16 - 45 and individual has not continuously been in education, follow process E1b: - //Either individual is currently a student and has left education at some point in the past (so returned) or individual is not a student so has not been in continuous education: - //TODO: If regression outcome of process E1b is true, set activity status to student and der (return to education indicator) to true? + // Use the same max age to leave cont. and discont. education - MAX_AGE_TO_LEAVE_CONTINUOUS_EDUCATION - double prob = Parameters.getRegEducationE1b().getProbability(this, Person.DoublesVariables.class); - if (labourInnov < prob) { - //If event is true, re-enter education. If event is false, leave school + // Case 3: Age 30+ and is a student + // Ensures that a student spends max 1 year in education + if (dag >= Parameters.MAX_AGE_TO_LEAVE_CONTINUOUS_EDUCATION && Les_c4.Student.equals(les_c4)) { + // Force out of education for all individuals age 30 or older + toLeaveSchool = true; + return !toLeaveSchool; // inSchool stops here; Case 1 and Case 2 are not considered + } + + + // Process E1b estimated on 16-35y.o. so consider only those individuals here + if (dag > Parameters.MAX_AGE_TO_ENTER_EDUCATION) { + return false; //inSchool stops here; Case 1 and Case 2 are not considered + } + + + // Case 1: Currently a student and always in education + if (Les_c4.Student.equals(les_c4) && !leftEducation) { + // Follow process E1a + double score = Parameters.getRegEducationE1a().getScore(this, Person.DoublesVariables.class); + double prob = Parameters.getRegEducationE1a().getProbability(score + probitAdjustment); + toLeaveSchool = (labourInnov >= prob); // Stay in school if event is false, leave otherwise + //Ded and Les_c4 remain the same if toLeaveSchool = false, no need to respecify them + //if toLeaveSchool = false, then Ded and Les_c4 are modified in the leavingSchool() method + } + + + // Case 2: Not continuously in education + else { + // Follow process E1b + double score = Parameters.getRegEducationE1b().getScore(this, Person.DoublesVariables.class); + double prob = Parameters.getRegEducationE1b().getProbability(score + probitAdjustment); + if (labourInnov < prob) { + // Remain or become a student setLes_c4(Les_c4.Student); setDer(Indicator.True); setDed(Indicator.True); - } else if (Les_c4.Student.equals(les_c4)){ - //If activity status is student but regression to be in education was evaluated to false, remove student status - - setLes_c4(Les_c4.NotEmployed); - setDed(Indicator.False); - toLeaveSchool = true; //Test what happens if people who returned to education leave again + toLeaveSchool = false; + } + else { + if (Les_c4.Student.equals(les_c4)) { + // toLeaveSchool process is initialised + toLeaveSchool = true; + } + else return false; // employed, not employed or retired, who do not become students, face no changes + // toLeaveSchool process is not initialised and their "inSchool" status set to false } - } else if (dag > 45 && les_c4.equals(Les_c4.Student)) { - //People above 45 shouldn't be in education, so if someone re-entered at 45 in previous step, force out - - setLes_c4(Les_c4.NotEmployed); - setDed(Indicator.False); } + + return !toLeaveSchool; } + protected void leavingSchool() { if (toLeaveSchool) { @@ -1517,34 +1541,7 @@ protected void updateNonLabourIncome() { else ypncp = 0.; //If no capital income, set amount to 0 } if (Les_c4.Retired.equals(les_c4)) { - // Retirement decision is modelled in the retirement process. Here only the amount of pension income for retired individuals is modelled. - /* - Private pension income when individual was retired in the previous period is modelled using process I4b. - - Private pension income when individual moves from non-retirement to retirement is modelled using: - i) process I5a_selection, to determine who receives private pension income - ii) process I5b_amount, for those who are determined to receive private pension income by process I5a_selection. I5b_amount is modelled in levels using linear regression. - */ - - double score, rmse, pensionIncLevel = 0.; - if (Les_c4.Retired.equals(les_c4_lag1)) { - // If person was retired in the previous period (and the simulation is not in its initial year), use process I4b - - score = Parameters.getRegIncomeI4b().getScore(this, Person.DoublesVariables.class); - rmse = Parameters.getRMSEForRegression("I4b"); - pensionIncLevel = setIncomeBySource(score, rmse, IncomeSource.PrivatePension, RegressionScoreType.Asinh); - } else { - // For individuals in the first year of retirement, use processes I5a_selection and I5b_amount - - double prob = Parameters.getRegIncomeI5a_selection().getProbability(this, Person.DoublesVariables.class); - boolean hasPrivatePensionIncome = (innovations.getDoubleDraw(19) < prob); - if (hasPrivatePensionIncome) { - - score = Parameters.getRegIncomeI5b_amount().getScore(this, Person.DoublesVariables.class); - rmse = Parameters.getRMSEForRegression("I5b"); - pensionIncLevel = setIncomeBySource(score, rmse, IncomeSource.PrivatePension, RegressionScoreType.Level); - } - } + double pensionIncLevel = 0.; ypnoab = Parameters.asinh(pensionIncLevel); } } @@ -1577,13 +1574,11 @@ public boolean atRiskOfWork() { return false; if (dag > Parameters.MAX_AGE_FLEXIBLE_LABOUR_SUPPLY) return false; - if (Les_c4.Retired.equals(les_c4) && !Parameters.enableIntertemporalOptimisations) - return false; - if (Les_c4.Student.equals(les_c4) && !Parameters.enableIntertemporalOptimisations) + if (Les_c4.Retired.equals(les_c4)) return false; - if (Indicator.True.equals(dlltsd) && !Parameters.flagSuppressSocialCareCosts) + if (Les_c4.Student.equals(les_c4)) return false; - if (Indicator.True.equals(needSocialCare) && !Parameters.flagSuppressSocialCareCosts) + if (Indicator.True.equals(dlltsd)) return false; //For cases where the participation equation used for the Heckmann Two-stage correction of the wage equation results in divide by 0 errors. @@ -1596,7 +1591,7 @@ public boolean atRiskOfWork() { } - // Assign education level to school leavers using MultiProbitRegression + // Assign education level to school leavers using Generalised Ordered Logit regression // Note that persons are now assigned a Low education level by default at birth (to prevent null pointer exceptions when persons become old enough to marry while still being a student // (we now allow students to marry, given they can re-enter school throughout their lives). // The module only applies to students who are leaving school (activityStatus == Student and toLeaveSchool == true) - see inSchool() @@ -1610,6 +1605,7 @@ private void setEducationLevel() { //This is because we no longer prevent people in school to get married, given that people can re-enter education throughout their lives. //Note that by not filtering out students, we must assign a low education level by default to persons at birth to prevent a null pointer exception when new born persons become old enough to marry if they have not yet left school because //their education level has not yet been assigned. + if (newEducationLevel.equals(Education.Low)) { model.lowEd++; } else if (newEducationLevel.equals(Education.Medium)) { @@ -1619,13 +1615,14 @@ private void setEducationLevel() { } else { model.nothing++; } - if(deh_c3 != null) { - if(newEducationLevel.ordinal() > deh_c3.ordinal()) { //Assume Education level cannot decrease after re-entering school. + if(der != null && der.equals(Indicator.True)) { + if(newEducationLevel.ordinal() >= deh_c3.ordinal()) { //Assume Education level cannot decrease after re-entering school. deh_c3 = newEducationLevel; } } else { deh_c3 = newEducationLevel; } + } public double getLiquidWealth() { @@ -1693,6 +1690,14 @@ protected void updateVariables(boolean initialUpdate) { } } + /* + Contemporaneous values of idPartner, dcpst, dhhtp_c4 are required for validation. Update and output here. + */ + private void updateOutputVariables() { + idPartner = getPartnerID(); + dcpst = getDcpst(); + } + private void updateLaggedVariables(boolean initialUpdate) { les_c4_lag1 = les_c4; @@ -2054,7 +2059,6 @@ public enum DoublesVariables { Covid_2021_D, Covid19GrossPayMonthly_L1, Covid19ReceivesSEISS_L1, - CovidTransitionsMonth, Cut1, // ordered probit/logit cut points - ignore these when evaluating score Cut2, Cut3, @@ -2065,14 +2069,15 @@ public enum DoublesVariables { Cut8, Cut9, Cut10, - D_children, - D_children_2under, // Indicator (dummy variables for presence of children of certain ages in the benefitUnit) - D_children_3_6, - D_children_7_12, - D_children_13_17, - D_children_18over, //Currently this will return 0 (false) as children leave home when they are 18 + D_Children, + D_Children_2under, // Indicator (dummy variables for presence of children of certain ages in the benefitUnit) + D_Children_3_6, + D_Children_7_12, + D_Children_13_17, + D_Children_18over, //Currently this will return 0 (false) as children leave home when they are 18 D_Econ_benefits, D_Home_owner, + Dhh_owned_L1, Dag, Dag_sq, DagCeiling54, @@ -2090,6 +2095,7 @@ public enum DoublesVariables { Deh_c3_Low, Deh_c3_Low_Dag, Deh_c3_Low_L1, //Education level lag(1) equals low + Deh_c3_High_L1, //Education level lag(1) equals low Deh_c3_Medium, Deh_c3_Medium_Dag, Deh_c3_Medium_L1, //Education level lag(1) equals medium @@ -2139,19 +2145,23 @@ public enum DoublesVariables { Dhhtp_c4_CoupleNoChildren_L1, Dhhtp_c4_SingleChildren_L1, Dhhtp_c4_SingleNoChildren_L1, + Dhhtp_c8_2_L1, + Dhhtp_c8_3_L1, + Dhhtp_c8_4_L1, + Dhhtp_c8_5_L1, + Dhhtp_c8_6_L1, + Dhhtp_c8_7_L1, + Dhhtp_c8_8_L1, Dhm, //Mental health status Dhm_L1, //Mental health status lag(1) Dhmghq_L1, Dlltsd, //Long-term sick or disabled Dlltsd_L1, //Long-term sick or disabled lag(1) + Dlltsdsp_L1, Dnc_L1, //Lag(1) of number of children of all ages in the benefitUnit Dnc02_L1, //Lag(1) of number of children aged 0-2 in the benefitUnit Dnc017, //Number of children aged 0-17 in the benefitUnit - EduHighIT, - EduMediumIT, EmployedToUnemployed, - Employmentsonflexiblefurlough, - Employmentsonfullfurlough, EquivalisedConsumptionYearly, EquivalisedIncomeYearly, //Equivalised income for use with the security index Female, @@ -2164,21 +2174,24 @@ public enum DoublesVariables { ITG, ITH, ITI, - LactiveIT, L1_hourly_wage, L1_log_hourly_wage, L1_log_hourly_wage_sq, Ld_children_2under, Ld_children_3under, - Ld_children_3underIT, Ld_children_4_12, - Ld_children_4_12IT, Lemployed, Lhw_L1, Les_c3_Employed_L1, Les_c3_NotEmployed_L1, Les_c3_Sick_L1, //This is based on dlltsd Les_c3_Student_L1, + Les_c4_Student_L1, + Les_c4_NotEmployed_L1, + Les_c4_Retired_L1, + Les_c4_Student_L1_Dgn, + Les_c4_NotEmployed_L1_Dgn, + Les_c4_Retired_L1_Dgn, Les_c7_Covid_Furlough_L1, Lesdf_c4_BothNotEmployed_L1, Lesdf_c4_EmployedSpouseNotEmployed_L1, //Own and partner's activity status lag(1) @@ -2191,7 +2204,6 @@ public enum DoublesVariables { Lnonwork, Lstudent, Lunion, - LunionIT, NeedCare_L1, NonPovertyToPoverty, NotEmployed_L1, @@ -2209,6 +2221,10 @@ public enum DoublesVariables { Reached_Retirement_Age, //Indicator whether individual is at or above retirement age Reached_Retirement_Age_Les_c3_NotEmployed_L1, //Interaction term for being at or above retirement age and not employed in the previous year Reached_Retirement_Age_Sp, //Indicator whether spouse is at or above retirement age + Elig_pen, // Age == state retirement age + Elig_pen_L1, // Age == state retirement age +1 + Elig_pen_Sp, // Partner's age == state retirement age + Elig_pen_L1_Sp, // // Partner's age == state retirement age +1 RealGDPGrowth, RealIncomeChange, //Note: the above return a 0 or 1 value, but income variables will return the change in income or 0 RealIncomeDecrease_D, @@ -2239,11 +2255,89 @@ public enum DoublesVariables { UKM, UKmissing, UKN, + PL4, + PL5, + PL6, + PL10, Year, //Year as in the simulation, e.g. 2009 + Year2010, + Year2011, + Year2012, + Year2013, + Year2014, + Year2015, + Year2016, + Year2017, + Year2018, + Year2019, + Year2020, + Y2020, + Year2021, + Y2021, + Year2022, + Year2023, + Year2024, + Year2025, + Year2026, + Year2027, + Year2028, + Year2029, + Year2030, + Year2031, + Year2032, + Year2033, + Year2034, + Year2035, + Year2036, + Year2037, + Year2038, + Year2039, + Year2040, + Year2041, + Year2042, + Year2043, + Year2044, + Year2045, + Year2046, + Year2047, + Year2048, + Year2049, + Year2050, + Year2051, + Year2052, + Year2053, + Year2054, + Year2055, + Year2056, + Year2057, + Year2058, + Year2059, + Year2060, + Year2061, + Year2062, + Year2063, + Year2064, + Year2065, + Year2066, + Year2067, + Year2068, + Year2069, + Year2070, + Year2071, + Year2072, + Year2073, + Year2074, + Year2075, + Year2076, + Year2077, + Year2078, + Year2079, Ydses_c5_Q2_L1, //HH Income Lag(1) 2nd Quantile Ydses_c5_Q3_L1, //HH Income Lag(1) 3rd Quantile Ydses_c5_Q4_L1, //HH Income Lag(1) 4th Quantile Ydses_c5_Q5_L1, //HH Income Lag(1) 5th Quantile + Ydses_L1, + Ydses_c5_L1, Year_transformed, //Year - 2000 Year_transformed_monetary, //Year-2000 that stops in 2017, for use with monetary processes Ynbcpdf_dv_L1, //Lag(1) of difference between own and partner's gross personal non-benefit income @@ -2259,6 +2353,7 @@ public enum DoublesVariables { Yptciihs_dv_L1, //Lag(1) of gross personal non-employment non-benefit income Yptciihs_dv_L2, //Lag(2) of gross personal non-employment non-benefit income Yptciihs_dv_L3, //Lag(3) of gross personal non-employment non-benefit income + New_rel_L1, // New relation indicator } public double getDoubleValue(Enum variableID) { @@ -2505,22 +2600,22 @@ public double getDoubleValue(Enum variableID) { return dcpst_lag1.equals(Dcpst.PreviouslyPartnered) ? 1. : 0.; } else return 0.; } - case D_children_2under -> { + case D_Children_2under -> { return (double) benefitUnit.getIndicatorChildren(0, 2).ordinal(); } - case D_children_3_6 -> { + case D_Children_3_6 -> { return (double) benefitUnit.getIndicatorChildren(3, 6).ordinal(); } - case D_children_7_12 -> { + case D_Children_7_12 -> { return (double) benefitUnit.getIndicatorChildren(7, 12).ordinal(); } - case D_children_13_17 -> { + case D_Children_13_17 -> { return (double) benefitUnit.getIndicatorChildren(13, 17).ordinal(); } - case D_children_18over -> { + case D_Children_18over -> { return (double) benefitUnit.getIndicatorChildren(18, 99).ordinal(); } - case D_children -> { + case D_Children -> { return (getNumberChildrenAll() > 0) ? 1. : 0.; } case Dnc_L1 -> { @@ -2645,6 +2740,9 @@ public double getDoubleValue(Enum variableID) { case Deh_c3_Low_L1 -> { return (Education.Low.equals(deh_c3_lag1)) ? 1.0 : 0.0; } + case Deh_c3_High_L1 -> { + return (Education.High.equals(deh_c3_lag1)) ? 1.0 : 0.0; + } case Dehm_c3_High -> { return (Education.High.equals(dehm_c3)) ? 1.0 : 0.0; } @@ -2690,12 +2788,67 @@ public double getDoubleValue(Enum variableID) { case Dhhtp_c4_SingleChildren_L1 -> { return (Dhhtp_c4.SingleChildren.equals(getDhhtp_c4_lag1())) ? 1.0 : 0.0; } + case Dhhtp_c8_2_L1 -> { + // Couple with no children, spouse student + Person partner = getPartner(); + if (partner != null && partner.les_c4_lag1 != null) + return (partner.les_c4_lag1.equals(Les_c4.Student) && Dhhtp_c4.CoupleNoChildren.equals(getDhhtp_c4_lag1())) ? 1. : 0.; + else + return 0.; + } + case Dhhtp_c8_3_L1 -> { + // Couple with no children, spouse not employed + Person partner = getPartner(); + if (partner != null && partner.les_c4_lag1 != null) + return ((partner.les_c4_lag1.equals(Les_c4.NotEmployed) || partner.les_c4_lag1.equals(Les_c4.Retired)) && Dhhtp_c4.CoupleNoChildren.equals(getDhhtp_c4_lag1())) ? 1. : 0.; + else + return 0.; + } + case Dhhtp_c8_4_L1 -> { + // Couple with children, spouse employed + Person partner = getPartner(); + if (partner != null && partner.les_c4_lag1 != null) + return (partner.les_c4_lag1.equals(Les_c4.EmployedOrSelfEmployed) && Dhhtp_c4.CoupleChildren.equals(getDhhtp_c4_lag1())) ? 1. : 0.; + else + return 0.; + } + case Dhhtp_c8_5_L1 -> { + // Couple with children, spouse student + Person partner = getPartner(); + if (partner != null && partner.les_c4_lag1 != null) + return (partner.les_c4_lag1.equals(Les_c4.Student) && Dhhtp_c4.CoupleChildren.equals(getDhhtp_c4_lag1())) ? 1. : 0.; + else + return 0.; + } + case Dhhtp_c8_6_L1 -> { + // Couple with children, spouse not employed + Person partner = getPartner(); + if (partner != null && partner.les_c4_lag1 != null) + return ((partner.les_c4_lag1.equals(Les_c4.NotEmployed) || partner.les_c4_lag1.equals(Les_c4.Retired)) && Dhhtp_c4.CoupleChildren.equals(getDhhtp_c4_lag1())) ? 1. : 0.; + else + return 0.; + } + case Dhhtp_c8_7_L1 -> { + // Single with no children + return Dhhtp_c4.SingleNoChildren.equals(getDhhtp_c4_lag1()) ? 1. : 0.; + } + case Dhhtp_c8_8_L1 -> { + // Single with children + return Dhhtp_c4.SingleChildren.equals(getDhhtp_c4_lag1()) ? 1. : 0.; + } case Dlltsd -> { return Indicator.True.equals(dlltsd) ? 1. : 0.; } case Dlltsd_L1 -> { return Indicator.True.equals(dlltsd_lag1) ? 1. : 0.; } + case Dlltsdsp_L1 -> { + Person partner = getPartner(); + if (partner != null && partner.dlltsd_lag1 != null) { + return Indicator.True.equals(partner.dlltsd_lag1) ? 1. : 0.; + } + else return 0.; + } case FertilityRate -> { if (ioFlag) return Parameters.getFertilityProjectionsByYear(getYear()); @@ -2743,6 +2896,24 @@ public double getDoubleValue(Enum variableID) { case Les_c3_Student_L1 -> { return (Les_c4.Student.equals(les_c4_lag1)) ? 1.0 : 0.0; } + case Les_c4_Student_L1 -> { + return (Les_c4.Student.equals(les_c4_lag1)) ? 1.0 : 0.0; + } + case Les_c4_NotEmployed_L1 -> { + return (Les_c4.NotEmployed.equals(les_c4_lag1)) ? 1.0 : 0.0; + } + case Les_c4_Retired_L1 -> { + return (Les_c4.Retired.equals(les_c4_lag1)) ? 1.0 : 0.0; + } + case Les_c4_Student_L1_Dgn -> { + return (Les_c4.Student.equals(les_c4_lag1) && Gender.Male.equals(dgn)) ? 1.0 : 0.0; + } + case Les_c4_NotEmployed_L1_Dgn -> { + return (Les_c4.NotEmployed.equals(les_c4_lag1) && Gender.Male.equals(dgn)) ? 1.0 : 0.0; + } + case Les_c4_Retired_L1_Dgn -> { + return (Les_c4.Retired.equals(les_c4_lag1) && Gender.Male.equals(dgn)) ? 1.0 : 0.0; + } case Les_c3_NotEmployed_L1 -> { return ((Les_c4.NotEmployed.equals(les_c4_lag1)) || (Les_c4.Retired.equals(les_c4_lag1))) ? 1.0 : 0.0; } @@ -2842,6 +3013,216 @@ public double getDoubleValue(Enum variableID) { case Year -> { return (Parameters.isFixTimeTrend && getYear() >= Parameters.timeTrendStopsIn) ? (double) Parameters.timeTrendStopsIn : (double) getYear(); } + case Year2010 -> { + return (getYear() <= 2010) ? 1. : 0.; + } + case Year2011 -> { + return (getYear() == 2011) ? 1. : 0.; + } + case Year2012 -> { + return (getYear() == 2012) ? 1. : 0.; + } + case Year2013 -> { + return (getYear() == 2013) ? 1. : 0.; + } + case Year2014 -> { + return (getYear() == 2014) ? 1. : 0.; + } + case Year2015 -> { + return (getYear() == 2015) ? 1. : 0.; + } + case Year2016 -> { + return (getYear() == 2016) ? 1. : 0.; + } + case Year2017 -> { + return (getYear() == 2017) ? 1. : 0.; + } + case Year2018 -> { + return (getYear() == 2018) ? 1. : 0.; + } + case Year2019 -> { + return (getYear() == 2019) ? 1. : 0.; + } + case Year2020, Y2020 -> { + return (getYear() == 2020) ? 1. : 0.; + } + case Year2021, Y2021 -> { + return (getYear() == 2021) ? 1. : 0.; + } + case Year2022 -> { + return (getYear() == 2022) ? 1. : 0.; + } + case Year2023 -> { + return (getYear() == 2023) ? 1. : 0.; + } + case Year2024 -> { + return (getYear() == 2024) ? 1. : 0.; + } + case Year2025 -> { + return (getYear() == 2025) ? 1. : 0.; + } + case Year2026 -> { + return (getYear() == 2026) ? 1. : 0.; + } + case Year2027 -> { + return (getYear() == 2027) ? 1. : 0.; + } + case Year2028 -> { + return (getYear() == 2028) ? 1. : 0.; + } + case Year2029 -> { + return (getYear() == 2029) ? 1. : 0.; + } + case Year2030 -> { + return (getYear() == 2030) ? 1. : 0.; + } + case Year2031 -> { + return (getYear() == 2031) ? 1. : 0.; + } + case Year2032 -> { + return (getYear() == 2032) ? 1. : 0.; + } + case Year2033 -> { + return (getYear() == 2033) ? 1. : 0.; + } + case Year2034 -> { + return (getYear() == 2034) ? 1. : 0.; + } + case Year2035 -> { + return (getYear() == 2035) ? 1. : 0.; + } + case Year2036 -> { + return (getYear() == 2036) ? 1. : 0.; + } + case Year2037 -> { + return (getYear() == 2037) ? 1. : 0.; + } + case Year2038 -> { + return (getYear() == 2038) ? 1. : 0.; + } + case Year2039 -> { + return (getYear() == 2039) ? 1. : 0.; + } + case Year2040 -> { + return (getYear() == 2040) ? 1. : 0.; + } + case Year2041 -> { + return (getYear() == 2041) ? 1. : 0.; + } + case Year2042 -> { + return (getYear() == 2042) ? 1. : 0.; + } + case Year2043 -> { + return (getYear() == 2043) ? 1. : 0.; + } + case Year2044 -> { + return (getYear() == 2044) ? 1. : 0.; + } + case Year2045 -> { + return (getYear() == 2045) ? 1. : 0.; + } + case Year2046 -> { + return (getYear() == 2046) ? 1. : 0.; + } + case Year2047 -> { + return (getYear() == 2047) ? 1. : 0.; + } + case Year2048 -> { + return (getYear() == 2048) ? 1. : 0.; + } + case Year2049 -> { + return (getYear() == 2049) ? 1. : 0.; + } + case Year2050 -> { + return (getYear() == 2050) ? 1. : 0.; + } + case Year2051 -> { + return (getYear() == 2051) ? 1. : 0.; + } + case Year2052 -> { + return (getYear() == 2052) ? 1. : 0.; + } + case Year2053 -> { + return (getYear() == 2053) ? 1. : 0.; + } + case Year2054 -> { + return (getYear() == 2054) ? 1. : 0.; + } + case Year2055 -> { + return (getYear() == 2055) ? 1. : 0.; + } + case Year2056 -> { + return (getYear() == 2056) ? 1. : 0.; + } + case Year2057 -> { + return (getYear() == 2057) ? 1. : 0.; + } + case Year2058 -> { + return (getYear() == 2058) ? 1. : 0.; + } + case Year2059 -> { + return (getYear() == 2059) ? 1. : 0.; + } + case Year2060 -> { + return (getYear() == 2060) ? 1. : 0.; + } + case Year2061 -> { + return (getYear() == 2061) ? 1. : 0.; + } + case Year2062 -> { + return (getYear() == 2062) ? 1. : 0.; + } + case Year2063 -> { + return (getYear() == 2063) ? 1. : 0.; + } + case Year2064 -> { + return (getYear() == 2064) ? 1. : 0.; + } + case Year2065 -> { + return (getYear() == 2065) ? 1. : 0.; + } + case Year2066 -> { + return (getYear() == 2066) ? 1. : 0.; + } + case Year2067 -> { + return (getYear() == 2067) ? 1. : 0.; + } + case Year2068 -> { + return (getYear() == 2068) ? 1. : 0.; + } + case Year2069 -> { + return (getYear() == 2069) ? 1. : 0.; + } + case Year2070 -> { + return (getYear() == 2070) ? 1. : 0.; + } + case Year2071 -> { + return (getYear() == 2071) ? 1. : 0.; + } + case Year2072 -> { + return (getYear() == 2072) ? 1. : 0.; + } + case Year2073 -> { + return (getYear() == 2073) ? 1. : 0.; + } + case Year2074 -> { + return (getYear() == 2074) ? 1. : 0.; + } + case Year2075 -> { + return (getYear() == 2075) ? 1. : 0.; + } + case Year2076 -> { + return (getYear() == 2076) ? 1. : 0.; + } + case Year2077 -> { + return (getYear() == 2077) ? 1. : 0.; + } + case Year2078 -> { + return (getYear() == 2078) ? 1. : 0.; + } + case Year2079 -> { + return (getYear() >= 2079) ? 1. : 0.; + } case Year_transformed -> { return (Parameters.isFixTimeTrend && getYear() >= Parameters.timeTrendStopsIn) ? (double) Parameters.timeTrendStopsIn - 2000 : (double) getYear() - 2000; } @@ -2860,6 +3241,11 @@ public double getDoubleValue(Enum variableID) { case Ydses_c5_Q5_L1 -> { return (Ydses_c5.Q5.equals(getYdses_c5_lag1())) ? 1.0 : 0.0; } + case Ydses_L1, Ydses_c5_L1 -> { + if (getYdses_c5_lag1() != null) { + return (double) getYdses_c5_lag1().getValue(); + } else return 0.; + } case Ypnbihs_dv_L1 -> { if (ypnbihs_dv_lag1 != null) { return ypnbihs_dv_lag1; @@ -2886,6 +3272,9 @@ public double getDoubleValue(Enum variableID) { case Yptciihs_dv_L3 -> { return yptciihs_dv_lag3; } + case New_rel_L1 -> { + return (getDcpst().equals(Dcpst.Partnered) && !dcpst_lag1.equals(Dcpst.Partnered))? 1. : 0.; + } case Ypncp_L1 -> { return ypncp_lag1; } @@ -2907,22 +3296,6 @@ public double getDoubleValue(Enum variableID) { case Yplgrs_dv_L3 -> { return yplgrs_dv_lag3; } - case Ld_children_3underIT -> { - return model.getCountry().equals(Country.IT) ? benefitUnit.getIndicatorChildren03_lag1().ordinal() : 0.; - } - case Ld_children_4_12IT -> { - return model.getCountry().equals(Country.IT) ? benefitUnit.getIndicatorChildren412_lag1().ordinal() : 0.; - } - case LunionIT -> { - return (household_status_lag.equals(HouseholdStatus.Couple) && (getRegion().toString().startsWith(Country.IT.toString()))) ? 1. : 0.; - } - case EduMediumIT -> { - return (deh_c3.equals(Education.Medium) && (getRegion().toString().startsWith(Country.IT.toString()))) ? 1. : 0.; - } - case EduHighIT -> { - return (deh_c3.equals(Education.High) && (getRegion().toString().startsWith(Country.IT.toString()))) ? 1. : 0.; - } - case Reached_Retirement_Age -> { int retirementAge; if (dgn.equals(Gender.Female)) { @@ -2946,6 +3319,53 @@ public double getDoubleValue(Enum variableID) { return 0.; } } + case Elig_pen -> { // Age == state retirement age + int retirementAge; + if (dgn.equals(Gender.Female)) { + retirementAge = (int) Parameters.getTimeSeriesValue(getYear(), Gender.Female.toString(), TimeSeriesVariable.FixedRetirementAge); + } else { + retirementAge = (int) Parameters.getTimeSeriesValue(getYear(), Gender.Male.toString(), TimeSeriesVariable.FixedRetirementAge); + } + return (dag == retirementAge) ? 1. : 0.; + } + case Elig_pen_L1 -> { // Age == state retirement age +1 + int retirementAge = 1; + if (dgn.equals(Gender.Female)) { + retirementAge += (int) Parameters.getTimeSeriesValue(getYear(), Gender.Female.toString(), TimeSeriesVariable.FixedRetirementAge); + } else { + retirementAge += (int) Parameters.getTimeSeriesValue(getYear(), Gender.Male.toString(), TimeSeriesVariable.FixedRetirementAge); + } + return (dag == retirementAge) ? 1. : 0.; + } + + case Elig_pen_Sp -> { // Partner's age == state retirement age + int retirementAgePartner; + Person partner = getPartner(); + if (partner != null) { + if (partner.dgn.equals(Gender.Female)) { + retirementAgePartner = (int) Parameters.getTimeSeriesValue(getYear(), Gender.Female.toString(), TimeSeriesVariable.FixedRetirementAge); + } else { + retirementAgePartner = (int) Parameters.getTimeSeriesValue(getYear(), Gender.Male.toString(), TimeSeriesVariable.FixedRetirementAge); + } + return (partner.dag == retirementAgePartner) ? 1. : 0.; + } else { + return 0.; + } + } + case Elig_pen_L1_Sp -> { // Partner's age == state retirement age +1 + int retirementAgePartner = 1; + Person partner = getPartner(); + if (partner != null) { + if (partner.dgn.equals(Gender.Female)) { + retirementAgePartner += (int) Parameters.getTimeSeriesValue(getYear(), Gender.Female.toString(), TimeSeriesVariable.FixedRetirementAge); + } else { + retirementAgePartner += (int) Parameters.getTimeSeriesValue(getYear(), Gender.Male.toString(), TimeSeriesVariable.FixedRetirementAge); + } + return (partner.dag >= retirementAgePartner) ? 1. : 0.; + } else { + return 0.; + } + } case Reached_Retirement_Age_Les_c3_NotEmployed_L1 -> { //Reached retirement age and was not employed in the previous year int retirementAge; if (dgn.equals(Gender.Female)) { @@ -3007,6 +3427,9 @@ public double getDoubleValue(Enum variableID) { case D_Home_owner -> { return getBenefitUnit().isDhhOwned() ? 1. : 0.; } // Evaluated at the level of a benefit unit. If required, can be changed to individual-level homeownership status. + case Dhh_owned_L1 -> { + return getBenefitUnit().isDhhOwned_lag1() ? 1. : 0.; + } case Covid_2020_D -> { return (getYear() == 2020) ? 1. : 0.; } @@ -3100,21 +3523,24 @@ public double getDoubleValue(Enum variableID) { return 0.; //For our purpose, all our simulated people have a region, so this enum value is always going to be 0 (false). // return (getRegion().equals(Region.UKmissing)) ? 1. : 0.; //For people whose region info is missing. The UK survey did not record the region in the first two waves (2006 and 2007, each for 4 years). For all those individuals we have gender, education etc but not region. If we exclude them we lose a large part of the UK sample, so this is the trick to keep them in the estimates. } + case PL4 -> { + return Region.PL4.equals(getRegion()) ? 1.0 : 0.0; + } + case PL5 -> { + return Region.PL5.equals(getRegion()) ? 1.0 : 0.0; + } + case PL6 -> { + return Region.PL6.equals(getRegion()) ? 1.0 : 0.0; + } + case PL10 -> { + return Region.PL10.equals(getRegion()) ? 1.0 : 0.0; + } // Regressors used in the Covid-19 labour market module below: case Dgn_Dag -> { if (dgn.equals(Gender.Male)) { return (double) dag; } else return 0.; } - case Employmentsonfullfurlough -> { - return Parameters.getEmploymentsFurloughedFullForMonthYear(model.getLabourMarket().getCovid19TransitionsMonth(), getYear()); - } - case Employmentsonflexiblefurlough -> { - return Parameters.getEmploymentsFurloughedFlexForMonthYear(model.getLabourMarket().getCovid19TransitionsMonth(), getYear()); - } - case CovidTransitionsMonth -> { - return model.getLabourMarket().getMonthForRegressor(); - } case Lhw_L1 -> { if (getNewWorkHours_lag1() != null) { return getNewWorkHours_lag1(); @@ -3357,6 +3783,15 @@ public void setDed(Indicator ded) { this.ded = ded; } + public int getLeaveSchool() { + if(toLeaveSchool != null && toLeaveSchool == true) { + return 1; + } + else { + return 0; + } + } + public int getLowEducation() { if(deh_c3 != null) { if (deh_c3.equals(Education.Low)) return 1; @@ -3458,6 +3893,14 @@ public void setToGiveBirth(boolean toGiveBirth_) { toGiveBirth = toGiveBirth_; } + public Boolean getToRetire() { + return toRetire; + } + + public void setToRetire(Boolean toRetire) { + this.toRetire = toRetire; + } + public boolean isToLeaveSchool() { return toLeaveSchool; } @@ -3520,6 +3963,13 @@ public Person getPartner() { return null; } + public Long getPartnerID() { + Person partner = this.getPartner(); + if (partner != null) { + return partner.getId(); + } else return null; + } + private void nullPartnerVariables() { careHoursFromPartnerWeekly = 0.0; @@ -3929,6 +4379,10 @@ public void setLiwwh(Integer liwwh) { this.liwwh = liwwh; } + public int getLiwwh() { + return liwwh != null? liwwh : 0 ; + } + public void setIoFlag(boolean ioFlag) { this.ioFlag = ioFlag; } diff --git a/src/main/java/simpaths/model/RetirementAlignment.java b/src/main/java/simpaths/model/RetirementAlignment.java new file mode 100644 index 000000000..415581e2c --- /dev/null +++ b/src/main/java/simpaths/model/RetirementAlignment.java @@ -0,0 +1,79 @@ +package simpaths.model; + +import microsim.engine.SimulationEngine; +import simpaths.data.IEvaluation; +import simpaths.data.Parameters; +import simpaths.data.filters.FertileFilter; +import simpaths.model.enums.Les_c4; +import simpaths.model.enums.TargetShares; + +import java.util.Set; + + +/** + * RetirementAlignment adjusts the probability of retiring. + * The object is designed to assist modification of the intercept of the "retirement" models. + * + * A search routine is used to find the value by which the intercept should be adjusted. + * If the projected share retired individuals in the population differs from the desired target by more than a specified threshold, + * then the intercept is adjusted and the share re-evaluated. + * + * Importantly, the adjustment needs to be only found once. Modified intercepts can then be used in subsequent simulations. + */ +public class RetirementAlignment implements IEvaluation { + + private double targetRetiredShare; + private Set persons; + private SimPathsModel model; + + + // CONSTRUCTOR + public RetirementAlignment(Set persons) { + this.model = (SimPathsModel) SimulationEngine.getInstance().getManager(SimPathsModel.class.getCanonicalName()); + this.persons = persons; + targetRetiredShare = Parameters.getTargetShare(model.getYear(), TargetShares.Retirement); + } + + + /** + * Evaluates the discrepancy between the simulated and target total retired share and adjusts probabilities if necessary. + * + * This method focuses on the influence of the adjustment parameter 'args[0]' on the difference between the target and + * simulated retired share (error). + * + * The error value is returned and serves as the stopping condition in root search routines. + * + * @param args An array of parameters, where args[0] represents the adjustment parameter. + * @return The error in the target aggregate share of retired persons after potential adjustments. + */ + @Override + public double evaluate(double[] args) { + + persons.parallelStream() + .forEach(person -> person.considerRetirement(args[0])); + + return targetRetiredShare - evalRetiredShare(); + } + + + /** + * Evaluates the aggregate share of persons with partners assigned in a test run of union matching among those eligible for partnership. + * + * This method uses Java streams to count the number of persons who meet the age criteria for cohabitation + * and the number of persons who currently have a test partner. The aggregate share is calculated as the + * ratio of successfully partnered persons to those eligible for partnership, with consideration for potential division by zero. + * + * @return The aggregate share of partnered persons among those eligible, or 0.0 if no eligible persons are found. + */ + private double evalRetiredShare() { + + long numRetiredPersons = model.getPersons().stream() + .filter(person -> (person.getToRetire().equals(true) || Les_c4.Retired.equals(person.getLes_c4()))) + .count(); + long numPeople = model.getPersons().stream() + .filter(person -> person.getLes_c4() != null) + .count(); + + return (numRetiredPersons > 0) ? (double) numRetiredPersons / numPeople : 0.0; + } +} diff --git a/src/main/java/simpaths/model/SimPathsModel.java b/src/main/java/simpaths/model/SimPathsModel.java index 0ca33d0e3..20988ad3e 100644 --- a/src/main/java/simpaths/model/SimPathsModel.java +++ b/src/main/java/simpaths/model/SimPathsModel.java @@ -16,6 +16,7 @@ import jakarta.persistence.EntityTransaction; import jakarta.persistence.Persistence; import jakarta.persistence.Transient; +import microsim.data.MultiKeyCoefficientMap; import org.apache.commons.lang3.ArrayUtils; import org.jetbrains.annotations.NotNull; import simpaths.data.IEvaluation; @@ -27,8 +28,6 @@ import microsim.alignment.outcome.ResamplingAlignment; import microsim.event.*; import microsim.event.EventListener; -import org.apache.commons.collections4.keyvalue.MultiKey; -import org.apache.commons.collections4.MapIterator; import org.apache.commons.collections4.map.LinkedMap; import org.apache.commons.collections4.map.MultiKeyMap; import org.apache.commons.lang3.tuple.Triple; @@ -39,13 +38,9 @@ // import JAS-mine packages import microsim.alignment.outcome.AlignmentOutcomeClosure; import microsim.annotation.GUIparameter; -import microsim.data.MultiKeyCoefficientMap; import microsim.data.db.DatabaseUtils; import microsim.engine.AbstractSimulationManager; import microsim.engine.SimulationEngine; -import microsim.matching.IterativeSimpleMatching; -import microsim.matching.MatchingClosure; -import microsim.matching.MatchingScoreClosure; // import LABOURsim packages import simpaths.data.Parameters; @@ -55,7 +50,6 @@ import simpaths.model.taxes.DonorTaxUnitPolicy; import simpaths.model.taxes.Match; import simpaths.model.taxes.Matches; -import simpaths.model.taxes.database.DatabaseExtension; import simpaths.model.taxes.database.TaxDonorDataParser; @@ -80,7 +74,7 @@ public void setFirstRun(boolean firstRun) { private static Logger log = Logger.getLogger(SimPathsModel.class); //@GUIparameter(description = "Country to be simulated") - private Country country; // = Country.UK; + private Country country; private boolean flagUpdateCountry = false; // set to true if switch between countries @@ -88,21 +82,21 @@ public void setFirstRun(boolean firstRun) { private Integer popSize = 170000; @GUIparameter(description = "Simulation first year [valid range 2011-2019]") - private Integer startYear = 2011; + private Integer startYear = 2019; @GUIparameter(description = "Simulation ends at year") - private Integer endYear = 2026; + private Integer endYear = 2040; @GUIparameter(description = "Maximum simulated age") - private Integer maxAge = 130; + private Integer maxAge = 81; //@GUIparameter(description = "Fix year used in the regressions to one specified below") private boolean fixTimeTrend = true; @GUIparameter(description = "Fix year used in the regressions to") - private Integer timeTrendStopsIn = 2021; + private Integer timeTrendStopsIn = 2022; - private Integer timeTrendStopsInMonetaryProcesses = 2021; // For monetary processes, time trend always continues to 2017 (last observed year in the estimation sample) and then values are grown at the growth rate read from Excel + private Integer timeTrendStopsInMonetaryProcesses = 2022; // For monetary processes, time trend always continues to 2017 (last observed year in the estimation sample) and then values are grown at the growth rate read from Excel // @GUIparameter(description="Age at which people in initial population who are not employed are forced to retire") // private Integer ageNonWorkPeopleRetire = 65; //The problem is that it is difficult to find donor benefitUnits for non-zero labour supply for older people who are in the Nonwork category but not Retired. They should, in theory, still enter the Labour Market Module, but if we cannot find donor benefitUnits, how should we proceed? We avoid this problem by defining that people over the age specified here are retired off if they have activity_status equal to Nonwork. @@ -163,15 +157,17 @@ public void setFirstRun(boolean firstRun) { private boolean alignPopulation = true; //TODO: routine fails to replicate results for minor variations between simulations // @GUIparameter(description = "If checked, will align fertility") - private boolean alignFertility = false; + private boolean alignFertility = true; + private boolean alignRetirement = false; + private boolean alignDisability = true; private boolean alignEducation = false; //Set to true to align level of education private boolean alignInSchool = false; //Set to true to align share of students among 16-29 age group - private boolean alignCohabitation = false; //Set to true to align share of couples (cohabiting individuals) + private boolean alignCohabitation = true; //Set to true to align share of couples (cohabiting individuals) - private boolean alignEmployment = false; //Set to true to align employment share + private boolean alignEmployment = true; //Set to true to align employment share public boolean addRegressionStochasticComponent = true; //If set to true, and regression contains ResStanDev variable, will evaluate the regression score including stochastic part, and omits the stochastic component otherwise. @@ -187,10 +183,10 @@ public void setFirstRun(boolean firstRun) { public boolean labourMarketCovid19On = false; // Set to true to use reduced-form labour market module for years affected by Covid-19 (2020, 2021) @GUIparameter(description = "Simulate formal childcare costs") - public boolean projectFormalChildcare = true; + public boolean projectFormalChildcare = false; @GUIparameter(description = "Average over donor pool when imputing transfer payments") - public boolean donorPoolAveraging = true; + public boolean donorPoolAveraging = false; private int ordering = Parameters.MODEL_ORDERING; //Used in Scheduling of model events. Schedule model events at the same time as the collector and observer events, but a lower order, so will be fired before the collector and observer have updated. @@ -240,11 +236,11 @@ public void setFirstRun(boolean firstRun) { EventGroup yearlySchedule = new EventGroup(); @GUIparameter(description = "tick to project social care") - private boolean projectSocialCare = true; + private boolean projectSocialCare = false; - private boolean flagSuppressChildcareCosts = false; + private boolean flagSuppressChildcareCosts = true; - private boolean flagSuppressSocialCareCosts = false; + private boolean flagSuppressSocialCareCosts = true; @GUIparameter(description = "tick to enable intertemporal optimised consumption and labour decisions") private boolean enableIntertemporalOptimisations = false; @@ -294,6 +290,19 @@ public void setFirstRun(boolean firstRun) { @GUIparameter(description = "whether to include geographic region in state space for IO behavioural solutions") private boolean responsesToRegion = false; + // Controls for macro shocks + @GUIparameter(description = "macro shock: population") + private MacroScenarioPopulation macroShockPopulation = MacroScenarioPopulation.Baseline; + + @GUIparameter(description = "macro shock: productivity") + private MacroScenarioProductivity macroShockProductivity = MacroScenarioProductivity.Baseline; + + @GUIparameter(description = "macro shock: green policy") + private MacroScenarioGreenPolicy macroShockGreenPolicy = MacroScenarioGreenPolicy.No; + + @GUIparameter(description = "macro shocks: on") + private boolean macroShocksOn = false; + RandomGenerator cohabitInnov; Random initialiseInnov1; Random initialiseInnov2; @@ -348,7 +357,7 @@ public void buildObjects() { Parameters.loadParameters(country, maxAge, enableIntertemporalOptimisations, projectFormalChildcare, projectSocialCare, donorPoolAveraging, fixTimeTrend, flagDefaultToTimeSeriesAverages, saveImperfectTaxDBMatches, timeTrendStopsIn, startYear, endYear, interestRateInnov, disposableIncomeFromLabourInnov, flagSuppressChildcareCosts, - flagSuppressSocialCareCosts); + flagSuppressSocialCareCosts, macroShockPopulation, macroShockProductivity, macroShockGreenPolicy, macroShocksOn); if (enableIntertemporalOptimisations) { alignEmployment = false; @@ -356,8 +365,6 @@ public void buildObjects() { responsesToHealth, minAgeForPoorHealth, responsesToDisability, responsesToRegion, responsesToEducation, responsesToPension, responsesToLowWageOffer, responsesToRetirement, saveBehaviour, readGrid, getEngine().getCurrentExperiment().getOutputFolder(), startYear, endYear); - //DecisionTests.compareGrids(); - //DatabaseExtension.extendInputData(); } long elapsedTime1 = System.currentTimeMillis(); System.out.println("Time to load parameters: " + (elapsedTime1 - elapsedTime0)/1000. + " seconds."); @@ -450,13 +457,8 @@ public void buildSchedule() { addEventToAllYears(Processes.StartYear); - if (enableIntertemporalOptimisations) - firstYearSched.addEvent(this, Processes.RationalOptimisation); - addEventToAllYears(Processes.UpdateParameters); addEventToAllYears(Processes.GarbageCollection); - if (enableIntertemporalOptimisations) - yearlySchedule.addCollectionEvent(benefitUnits, BenefitUnit.Processes.UpdateWealth); addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.Update); addCollectionEventToAllYears(persons, Person.Processes.Update); @@ -468,29 +470,28 @@ public void buildSchedule() { //yearlySchedule.addEvent(this, Processes.CheckForEmptyHouseholds); // Check whether persons have reached retirement Age - addCollectionEventToAllYears(persons, Person.Processes.ConsiderRetirement, false); + yearlySchedule.addEvent(this, Processes.RetirementAlignment); + yearlySchedule.addCollectionEvent(persons, Person.Processes.ConsiderRetirement, false); // EDUCATION MODULE // Check In School - check whether still in education, and if leaving school, reset Education Level yearlySchedule.addCollectionEvent(persons, Person.Processes.InSchool); // In School alignment - addEventToAllYears(Processes.InSchoolAlignment); - addCollectionEventToAllYears(persons, Person.Processes.LeavingSchool); + yearlySchedule.addEvent(this, Processes.InSchoolAlignment); + yearlySchedule.addCollectionEvent(persons, Person.Processes.LeavingSchool); // Align the level of education if required - addEventToAllYears(Processes.EducationLevelAlignment); + yearlySchedule.addEvent(this, Processes.EducationLevelAlignment); // Homeownership status yearlySchedule.addCollectionEvent(benefitUnits, BenefitUnit.Processes.Homeownership); // HEALTH MODULE // Update Health - determine health (continuous) based on regression models: done here because health depends on education + yearlySchedule.addEvent(this, Processes.DisabilityAlignment); yearlySchedule.addCollectionEvent(persons, Person.Processes.Health); - // Update mental health - determine (continuous) mental health level based on regression models - yearlySchedule.addCollectionEvent(persons, Person.Processes.HealthMentalHM1); //Step 1 of mental health - // HOUSEHOLD COMPOSITION MODULE: Decide whether to enter into a union (marry / cohabit), and then perform union matching (marriage) between a male and female // Update potential earnings so that as up to date as possible to decide partner in union matching. @@ -512,42 +513,17 @@ public void buildSchedule() { yearlySchedule.addCollectionEvent(persons, Person.Processes.GiveBirth, false); //Cannot use read-only collection schedule as newborn children cause concurrent modification exception. Need to specify false in last argument of Collection event. // TIME USE MODULE - // Social care - if (projectSocialCare) { - addCollectionEventToAllYears(persons, Person.Processes.SocialCareReceipt); - addCollectionEventToAllYears(persons, Person.Processes.SocialCareProvision); - //yearlySchedule.addEvent(this, Processes.SocialCareMarketClearing); - } - - // Unemployment - addCollectionEventToAllYears(persons, Person.Processes.Unemployment); - - // update references for optimising behaviour - // needs to be positioned after all decision states for the current period have been simulated - if (enableIntertemporalOptimisations) - addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.UpdateStates, false); - addEventToAllYears(Processes.LabourMarketAndIncomeUpdate); // Assign benefit status to individuals in benefit units, from donors. Based on donor tax unit status. addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.ReceivesBenefits); // CONSUMPTION AND SAVINGS MODULE - if (enableIntertemporalOptimisations) - addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.ProjectDiscretionaryConsumption); addCollectionEventToAllYears(persons, Person.Processes.ProjectEquivConsumption); // equivalised disposable income addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.CalculateChangeInEDI); - // MENTAL HEALTH MODULE - // Update mental health - determine (continuous) mental health level based on regression models + caseness - addCollectionEventToAllYears(persons, Person.Processes.HealthMentalHM1); //Step 1 of mental health - // modify the outcome of Step 1 depending on individual's exposures + caseness - addCollectionEventToAllYears(persons, Person.Processes.HealthMentalHM2); //Step 2 of mental health. - // update case-based measure - addCollectionEventToAllYears(persons, Person.Processes.HealthMentalHM1HM2Cases); - // mortality (migration) and population alignment at year's end addCollectionEventToAllYears(persons, Person.Processes.ConsiderMortality); addEventToAllYears(Processes.PopulationAlignment); @@ -555,6 +531,8 @@ public void buildSchedule() { // END OF YEAR PROCESSES addEventToAllYears(Processes.CheckForImperfectTaxDBMatches); addEventToAllYears(tests, Tests.Processes.RunTests); //Run tests + addCollectionEventToAllYears(persons, Person.Processes.UpdateOutputVariables); // Update idPartner, dhhtp_c4 + addCollectionEventToAllYears(benefitUnits, BenefitUnit.Processes.UpdateOutputVariables); // Update dhhtp_c4 addEventToAllYears(Processes.EndYear); // UPDATE YEAR @@ -566,7 +544,6 @@ public void buildSchedule() { // at termination of simulation int orderEarlier = -1; //Set less than order so that this is called before the yearlySchedule in the endYear. - getEngine().getEventQueue().scheduleOnce(new SingleTargetEvent(this, Processes.CleanUp), endYear+1, orderEarlier); SystemEvent end = new SystemEvent(SimulationEngine.getInstance(), SystemEventType.End); getEngine().getEventQueue().scheduleOnce(end, endYear+1, orderEarlier); @@ -734,6 +711,8 @@ public enum Processes { FertilityAlignment, PopulationAlignment, CohabitationAlignment, + RetirementAlignment, + DisabilityAlignment, // HealthAlignment, InSchoolAlignment, EducationLevelAlignment, @@ -746,7 +725,6 @@ public enum Processes { CheckForEmptyBenefitUnits, GarbageCollection, CheckForImperfectTaxDBMatches, - CleanUp, } @Override @@ -759,7 +737,7 @@ public void onEvent(Enum type) { if (commentsOn) log.info("Starting year " + year); } case EndYear -> { - + //System.out.println("Model assigned " + lowEd + "low education levels, " + medEd + "medium, " + highEd + "high ed"); long elapsedTime1 = System.currentTimeMillis(); double timerForYear = (elapsedTime1 - elapsedTime0)/1000.0; System.out.println("Finished year " + year + " (in " + timerForYear + " seconds)"); @@ -792,15 +770,25 @@ public void onEvent(Enum type) { } clearPersonsToMatch(); } + case RetirementAlignment -> { + if (alignRetirement) { + retirementAlignment(); + if (commentsOn) log.info("Retirement alignment complete."); + } + } + case DisabilityAlignment -> { + if (alignDisability) { + disabilityAlignment(); + if (commentsOn) log.info("Disability alignment complete."); + } + } // case HealthAlignment -> { // healthAlignment(); // if (commentsOn) log.info("Health alignment complete."); // } case UnionMatching -> { - if(UnionMatchingMethod.SBAM.equals(unionMatchingMethod)) { - unionMatchingSBAM(); - } else if (UnionMatchingMethod.Parametric.equals(unionMatchingMethod)) { + if (UnionMatchingMethod.Parametric.equals(unionMatchingMethod)) { unionMatching(false); } else { unionMatching(false); @@ -868,11 +856,6 @@ public void onEvent(Enum type) { screenForImperfectTaxDbMatches(); } } - case CleanUp -> { - - if (Parameters.saveImperfectTaxDBMatches) - DatabaseExtension.extendInputData(getEngine().getCurrentExperiment().getOutputFolder()); - } default -> { throw new RuntimeException("failed to identify process type in SimPathsModel.onEvent"); } @@ -1386,391 +1369,6 @@ private BenefitUnit cloneBenefitUnit(BenefitUnit originalBenefitUnit, Household } - /** - * - * PROCESS - HEALTH ALIGNMENT OF SIMULATED POPULATION - * - */ - /* - //TODO: The health alignment might have to be handled differently with continuous health - private void healthAlignment() { - - for (Gender gender: Gender.values()) { - for (int age = Parameters.MIN_AGE_TO_ALIGN_HEALTH; age <= Parameters.getFixedRetireAge(year, gender); age++) { - - //Target proportion - double proportionWithBadHealth = ((Number)Parameters.getProbSick().get(gender, age)).doubleValue(); - - //People to be aligned in gender-age specific cell - Set personsWithGenderAndAge = new LinkedHashSet(); - for (Region region: Parameters.getCountryRegions()) { - personsWithGenderAndAge.addAll(personsByGenderRegionAndAge.get(gender, region, age)); - } - - //Align - new ResamplingWeightedAlignment().align( - personsWithGenderAndAge, - null, - new AlignmentOutcomeClosure() { - - @Override - public boolean getOutcome(Person agent) { - return agent.getDhe() == 1.; //TODO: Check the new continuous health status - } - - @Override - public void resample(Person agent) { - //Swap health status - if (agent.getDhe() > 1.) { - agent.setDhe(1.); - } else { - agent.setDhe(3.); //TODO: What numerical value should correspond to "good" health? - } - } - - }, - proportionWithBadHealth - ); - } - } - } - */ - - /* - * unionMatchingSBAM implements a marriage matching method presented by Stephensen 2013. - */ - - int partnershipsCreated = 0; - int malesUnmatched = 0; - int femalesUnmatched = 0; - - @SuppressWarnings("unchecked") - private void unionMatchingSBAM() { - - int malesToBePartnered = 0; - int femalesToBePartnered = 0; - partnershipsCreated = 0; - - for (Person p : persons) { - if (p.isToBePartnered() == true) { - if (p.getDgn().equals(Gender.Male)) malesToBePartnered++; - else if (p.getDgn().equals(Gender.Female)) femalesToBePartnered++; - } - } - -// System.out.println("Number of males to be partnered is " + malesToBePartnered + " , number of females to be partnered is " + femalesToBePartnered); - - /* If adjustZeroEntries = true, zero frequencies are set to a very small number (1.e-6) for combinations of types that theoretically could occur. This are unlikely to result in any actual matches, - * as they are set to nearest integer, but allow the matches we are interested in to be adjusted. (One possibility is to introduce matching with probability equal to the frequency for such combinations). - */ - boolean adjustZeroEntries = true; - - //1. Load distribution of marriages observed in Excel using ExcelLoader from marriageTypes2.xlsx file. Store a copy in marriageTypesToAdjust, which is - // a MultiKeyCoefficientMap - it has 2 string keys that identify a value. 1st key is person type, 2nd key is partner type, value is the number of marriages between these types - // observed in the data. - MultiKeyCoefficientMap marriageTypesToAdjustMap = Parameters.getMarriageTypesFrequency().clone(); //Clone the original map loaded from Excel to adjust frequencies on a copy - - //Create a set of keys on which the types are defined: currently Gender, Region, Education, Age Group - Set keysMultiKeySet = new LinkedHashSet(); - Set keysStringSet = new LinkedHashSet(); - for(Gender gender : Gender.values()) { - - for(Region region : Parameters.getCountryRegions()) { - - Set tmpPersonsSet = new LinkedHashSet(); - tmpPersonsSet.addAll(personsToMatch.get(gender).get(region)); //Using currently defined process for cohabitation, add all people who want to match to a set - - //The set of people who want to match can be further divided based on observables, e.g. we include Education. This must match the Excel file with frequencies, also in order of variables - for (Education education : Education.values()) { - - for(int ageGroup = 0; ageGroup <= 11; ageGroup++) { - - Set tmpPersonsSet2 = new LinkedHashSet(); //Add to this set people from tmpPersonsSet selected on further observables - String tmpKeyString = gender + " " + region + " " + education + " " + ageGroup; //MultiKey defined above, but for most methods we use a composite String key instead as MultiKeyMap has a limit of keys - for (Person person : tmpPersonsSet) { - - if (person.getDeh_c3().equals(education) && person.getAgeGroup() == ageGroup) tmpPersonsSet2.add(person); //If education level matches add person to the set - } - - personsToMatch2.put(tmpKeyString, tmpPersonsSet2); //Add a key and set of people to set of persons to match. Each key corresponds to a set of people of certain Gender, Region, and Education who want to match - - //Now add the number of people to match for gender, region, education as target - double tmpTargetDouble = personsToMatch2.get(tmpKeyString).size(); - - //Create a set containing row keys of marriageTypesToAdjust: - Set tmpKeysStringSet = new LinkedHashSet(); - MapIterator frequenciesIterator = marriageTypesToAdjustMap.mapIterator(); - while (frequenciesIterator.hasNext()) { - - frequenciesIterator.next(); - MultiKey tmpKeyMultiKey = (MultiKey) frequenciesIterator.getKey(); - String key0String = tmpKeyMultiKey.getKey(0).toString(); - tmpKeysStringSet.add(key0String); //The only types not in the set should be those that don't have any matches in the data - } - - if(tmpKeysStringSet.contains(tmpKeyString)) { //Check if the target is contained in frequencies from the data - if not, 0 entries cannot be adjusted anyway - - marriageTargetsByKey.put(tmpKeyString, tmpTargetDouble); //Update marriageTargetByKey - MultiKey tmpKeyMultiKey = new MultiKey(gender, region, education, ageGroup); - keysMultiKeySet.add(tmpKeyMultiKey); //Add MultiKey to set of keys - keysStringSet.add(tmpKeyString); - } - } - } - } - } - - //For sparse matrix with only few positive entries, convergence is not very good. One way to deal with it is to use very small numbers instead of 0 for matches that - //theoretically could occur? (i.e. no same sex matches, and no cross-region matches) but were not observed in the data. - if(adjustZeroEntries) { - - for (MultiKey key1 : keysMultiKeySet) { //For each row in the frequency matrix - - Gender gender1 = (Gender) key1.getKey(0); - Region region1 = (Region) key1.getKey(1); - Education education1 = (Education) key1.getKey(2); - int ageGroup1 = (int) key1.getKey(3); - String key1String = gender1 + " " + region1 + " " + education1 + " " + ageGroup1; - // System.out.println(); - for(MultiKey key2 : keysMultiKeySet) { //For each column - - Gender gender2 = (Gender) key2.getKey(0); - Region region2 = (Region) key2.getKey(1); - Education education2 = (Education) key2.getKey(2); - int ageGroup2 = (int) key2.getKey(3); - String key2String = gender2 + " " + region2 + " " + education2 + " " + ageGroup2; - if(marriageTypesToAdjustMap.get(key1String, key2String) != null) { //Value present, do nothing - - } else if(!key1String.equals(key2String)) { //Null value, if not the same type, set to small number - - marriageTypesToAdjustMap.put(key1String, key2String, 1.e-6); - } - //else { - // marriageTypesToAdjust.put(key1String, key2String, 0.); //Same sex and cross-region matches to have 0 frequency -> this is now handled in the matching closure, by not matching such couples - //} - // System.out.print(marriageTypesToAdjust.get(key1String, key2String) + " "); - } - } - } - - //Iterate as on a matrix until the cumulative difference between frequencies in marriageTypesToAdjust and the targets from marriageTargetsByKey is smaller than the specified precision: - int tmpCountInt = 0; - double errorDouble = Double.MAX_VALUE; - double precisionDouble = 1.e-1; - while ((errorDouble >= precisionDouble) && tmpCountInt < 10) { //100 iteration should be enough for the algorithm to converge, but this can be relaxed - - errorDouble = 0.; - - //These maps will hold row and column sums (updated in each iteration) - LinkedHashMap rowSumsMap = new LinkedHashMap(); - LinkedHashMap colSumsMap = new LinkedHashMap(); - - //These maps will hold row and column multipliers (updated in each iteration, and defined as Target/Sum_of_frequencies) - LinkedHashMap rowMprMap = new LinkedHashMap(); - LinkedHashMap colMprMap = new LinkedHashMap(); - - //Instead of iterating through rows and columns, go through every element of the map and add to the row / col sum depending on key1 and key2 - //marriageTypesToAdjust is a map, where key is a MultiKey with two values (Strings): first value identifies one type, second value identifies second type, value stores the frequency of matches. - //Instead of iterating through rows and columns, can iterate through each cell of the map and add it to rowSum (and later on to colSum). - MapIterator frequenciesIterator = marriageTypesToAdjustMap.mapIterator(); - - while (frequenciesIterator.hasNext()) { - - frequenciesIterator.next(); - MultiKey tmpKeyMultiKey = (MultiKey) frequenciesIterator.getKey(); //Get MultiKey identifying each cell (mk.getKey(0) is row, mk.getKey(1) is column) - double tmpValueDouble = 0.; - if (rowSumsMap.get(tmpKeyMultiKey.getKey(0).toString()) == null) { //If null value in rowSumsMap, then just put the current value, otherwise add - - tmpValueDouble = ((Number) frequenciesIterator.getValue()).doubleValue(); - } else { - - tmpValueDouble = rowSumsMap.get(tmpKeyMultiKey.getKey(0).toString()) + ((Number) frequenciesIterator.getValue()).doubleValue(); - } - - //To get row sums add value to a map where key0 is the key - rowSumsMap.put(tmpKeyMultiKey.getKey(0).toString(), tmpValueDouble); - } - //Get target by key and divide by row sum for that key to get row multiplier, same for column later on - marriageTargetsByKey.keySet().iterator().forEachRemaining(key -> rowMprMap.put(key, marriageTargetsByKey.get(key)/rowSumsMap.get(key))); - - //After the first iteration, rowSum might = 0 which means division is undefined resulting in null rowMpr entry - adjust to 0 if that happens - rowMprMap.keySet().iterator().forEachRemaining(key -> { - - if(rowMprMap.get(key).isNaN()) rowMprMap.put(key, 0.); - if(rowMprMap.get(key).isInfinite()) rowMprMap.put(key, 0.); - }); - - //Now knowing the row multiplier, multiply entries in the frequency map (marriageTypesToAdjust) - frequenciesIterator = marriageTypesToAdjustMap.mapIterator(); - while (frequenciesIterator.hasNext()) { - - frequenciesIterator.next(); - MultiKey tmpKeyMultiKey = (MultiKey) frequenciesIterator.getKey(); - double tmpValueDouble = ((Number) frequenciesIterator.getValue()).doubleValue(); - tmpValueDouble *= rowMprMap.get(tmpKeyMultiKey.getKey(0).toString()); - frequenciesIterator.setValue(tmpValueDouble); - } - - //Have to repeat for columns: - frequenciesIterator = marriageTypesToAdjustMap.mapIterator(); - while (frequenciesIterator.hasNext()) { - - frequenciesIterator.next(); - MultiKey tmpKeyMultiKey = (MultiKey) frequenciesIterator.getKey(); - double tmpValueDouble = 0.; - if (colSumsMap.get(tmpKeyMultiKey.getKey(1).toString()) == null) { - - tmpValueDouble = ((Number) frequenciesIterator.getValue()).doubleValue(); - } else { - - tmpValueDouble = colSumsMap.get(tmpKeyMultiKey.getKey(1).toString()) + ((Number) frequenciesIterator.getValue()).doubleValue(); - } - - //To get column sums add value to a map where key1 is the key - colSumsMap.put(tmpKeyMultiKey.getKey(1).toString(), tmpValueDouble); - } - - marriageTargetsByKey.keySet().iterator().forEachRemaining(key -> colMprMap.put(key, marriageTargetsByKey.get(key)/colSumsMap.get(key))); - - //As for rows, make sure multipliers are defined - colMprMap.keySet().iterator().forEachRemaining(key -> { - - if(colMprMap.get(key).isNaN()) colMprMap.put(key, 0.); - if(colMprMap.get(key).isInfinite()) colMprMap.put(key, 0.); - }); - - //Now knowing the col multiplier, multiply entries in the map with frequencies - frequenciesIterator = marriageTypesToAdjustMap.mapIterator(); - while (frequenciesIterator.hasNext()) { - - frequenciesIterator.next(); - MultiKey tmpKeyMultiKey = (MultiKey) frequenciesIterator.getKey(); - double tmpValueDouble = ((Number) frequenciesIterator.getValue()).doubleValue(); - tmpValueDouble *= colMprMap.get(tmpKeyMultiKey.getKey(1).toString()); - frequenciesIterator.setValue(tmpValueDouble); - } - - //Calculate error as the cumulative difference between targets and row and column sums - for (String key : marriageTargetsByKey.keySet()) { - - errorDouble += Math.abs(marriageTargetsByKey.get(key) - rowSumsMap.get(key)); - errorDouble += Math.abs(marriageTargetsByKey.get(key) - colSumsMap.get(key)); - } - - // System.out.println("Error is " + error + " and iteration is " + tmpCount); - // System.out.print("."); - tmpCountInt++; - } - - //Print out adjusted frequencies - marriageTypesToAdjustMap.keySet().iterator().forEachRemaining(key -> System.out.println(key + "=" + marriageTypesToAdjustMap.get(key))); - - /* - * Use matching method provided with JAS-mine: - */ - for(String key : keysStringSet) { - - for(String keyOther : keysStringSet) { - - //Get number of people that should be matched for key, keyOther combination - int tmpTargetInt; - if(marriageTypesToAdjustMap.get(key, keyOther) != null) { - - tmpTargetInt = (int) Math.round(((Number) marriageTypesToAdjustMap.getValue(key, keyOther)).doubleValue()); - } else tmpTargetInt = 0; - - //Check if for the combination of key, keyOther matches should be formed: - if (tmpTargetInt > 0) { - - double initialSizeQ1Double = personsToMatch2.get(key).size(); //Number of people to match ("row") - Set unmatchedQ1Set = new LinkedHashSet(); //Empty set to store people to match - unmatchedQ1Set.addAll(personsToMatch2.get(key)); //Add people to match - -// unmatchedQ1.stream().iterator().forEachRemaining(persontodisp -> System.out.println("PID " + persontodisp.getKey().getId() + " HHID " + persontodisp.getHousehold().getKey().getId())); - -// System.out.println("Matching "+ initialSizeQ1 +" persons from " + key + " to " + keyOther); - - double initialSizeQ2Double = personsToMatch2.get(keyOther).size(); //Number of people to match with ("column") - Set unmatchedQ2FullSet = new HashSet(); // Empty set to store people to match with (note that HashSet does not preserve order, so we will sample at random from it) - unmatchedQ2FullSet.addAll(personsToMatch2.get(keyOther)); //Add people to match with - Set unmatchedQ2Set = new LinkedHashSet(); - - //Keep only the number of people in unmatchedQ2 that is equal to the adjusted number of matches to create from marriageTypesToAdjust: - Iterator unmatchedQ2FullSetIterator = unmatchedQ2FullSet.iterator(); - for(int n = 0; n < tmpTargetInt && unmatchedQ2FullSetIterator.hasNext(); n++) { - - Person person = unmatchedQ2FullSetIterator.next(); - unmatchedQ2Set.add(person); - } - - /* - System.out.println("Currently matching " + key + " with " + keyOther + ". The target is " + tmpTarget + " and there are " + unmatchedQ1.size() + - " people in Q1 and " + unmatchedQ2.size() + " in Q2. (Originally Q2 had " + unmatchedQ2full.size() + " people."); - unmatchedQ2.stream().iterator().forEachRemaining(persontodisp -> System.out.println("PID " + persontodisp.getKey().getId() + " HHID " + persontodisp.getHousehold().getKey().getId())); - */ - Pair, Set> unmatchedSetsPair = new Pair<>(unmatchedQ1Set, unmatchedQ2Set); - //System.out.println("People in Q1 = " + unmatched.getFirst().size() + " People in Q2 = " + unmatched.getSecond().size()); - unmatchedSetsPair = IterativeSimpleMatching.getInstance().matching( - unmatchedSetsPair.getFirst(), null, null, unmatchedSetsPair.getSecond(), null, - - //This closure calculates the score for potential couple - new MatchingScoreClosure() { - @Override - public Double getValue(Person male, Person female) { - - return cohabitInnov.nextDouble(); //Random matching score - } - }, - - new MatchingClosure() { - @Override - public void match(Person p1, Person p2) { - - //If two people have the same gender or different region, simply don't match and do nothing? - if (p1.getDgn().equals(p2.getDgn()) || !p1.getRegion().equals(p2.getRegion())) { - // throw new RuntimeException("Error - both parties to match have the same gender!"); - } else { - - p1.setDcpyy(0); //Set years in partnership to 0 - p2.setDcpyy(0); - - // update benefit unit and household - p1.setupNewBenefitUnit(p2, true); - p1.setToBePartnered(false); //Probably could be removed - p2.setToBePartnered(false); - personsToMatch2.get(key).remove(p1); //Remove matched persons and keep everyone else in the matching queue - personsToMatch2.get(keyOther).remove(p2); - personsToMatch.get(p1.getDgn()).get(p1.getRegion()).remove(p1); - personsToMatch.get(p2.getDgn()).get(p2.getRegion()).remove(p2); - partnershipsCreated++; - } - } - } - ); - } - } - - Set unmatchedSet = new LinkedHashSet<>(); - unmatchedSet.addAll(personsToMatch2.get(key)); - for (Person unmatchedPerson : unmatchedSet) { - - if (unmatchedPerson.getDgn().equals(Gender.Male)) malesUnmatched++; - else if (unmatchedPerson.getDgn().equals(Gender.Female)) femalesUnmatched++; - } - - /* - personsToMatch2.get(key).clear(); - for(Gender gender: Gender.values()) { - for(Region region : Parameters.getCountryRegions()) { - personsToMatch.get(gender).get(region).clear(); - } - } - */ - } - - // System.out.println("Total over all years of unmatched males is " + malesUnmatched + " and females " + femalesUnmatched); - } - /** * * PROCESS - UNION MATCHING OF SIMULATED POPULATION @@ -1852,10 +1450,71 @@ private void socialCareMarketClearing() { } } + public void retirementAlignment() { + RetirementAlignment retirementAlignment = new RetirementAlignment(persons); + double retirementAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.RetirementAdjustment); + RootSearch search = getRootSearch(retirementAdjustment, retirementAlignment, 1.0E-2, 1.0E-2, 10); // epsOrdinates and epsFunction determine the stopping condition for the search. For retirementAlignment error term is the difference between target and observed share of partnered individuals. + + // update and exit + if (search.isTargetAltered()) { + Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.RetirementAdjustment); // If adjustment is altered from the initial value, update the map + System.out.println("Retirement adjustment value was " + search.getTarget()[0]); + } + } + + public void disabilityAlignment() { + DisabilityAlignment disabilityAlignment = new DisabilityAlignment(persons); + double disabilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.DisabilityAdjustment); + RootSearch search = getRootSearch(disabilityAdjustment, disabilityAlignment, 5.0E-3, 5.0E-3, 2); + + // update and exit + if (search.isTargetAltered()) { + Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.DisabilityAdjustment); // If adjustment is altered from the initial value, update the map + System.out.println("Disability adjustment value was " + search.getTarget()[0]); + } + } + + public void activityAlignmentMacroShock() { + Map coefficientMaps = new HashMap<>(); + coefficientMaps.put(OccupancyMacroShock.Single_Male, Parameters.getCoeffLabourSupplyUtilityMales()); + coefficientMaps.put(OccupancyMacroShock.Single_Female, Parameters.getCoeffLabourSupplyUtilityFemales()); + coefficientMaps.put(OccupancyMacroShock.Couple, Parameters.getCoeffLabourSupplyUtilityCouples()); + coefficientMaps.put(OccupancyMacroShock.Male_AC, Parameters.getCoeffLabourSupplyUtilityACMales()); + coefficientMaps.put(OccupancyMacroShock.Female_AC, Parameters.getCoeffLabourSupplyUtilityACFemales()); + coefficientMaps.put(OccupancyMacroShock.Male_With_Dependent, Parameters.getCoeffLabourSupplyUtilityMalesWithDependent()); + coefficientMaps.put(OccupancyMacroShock.Female_With_Dependent, Parameters.getCoeffLabourSupplyUtilityFemalesWithDependent()); + + Map> regressorsToModify = new HashMap<>(); + regressorsToModify.put(OccupancyMacroShock.Single_Male, List.of("MaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Single_Female, List.of("FemaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Couple, List.of("MaleLeisure", "FemaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Male_AC, List.of("MaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Female_AC, List.of("FemaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Male_With_Dependent, List.of("MaleLeisure")); + regressorsToModify.put(OccupancyMacroShock.Female_With_Dependent, List.of("FemaleLeisure")); + + double initialUtilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.UtilityAdjustment); + + ActivityAlignmentMacroShock activityAlignment = new ActivityAlignmentMacroShock( + persons, benefitUnits, coefficientMaps, regressorsToModify, initialUtilityAdjustment + ); + + RootSearch search = getRootSearch(initialUtilityAdjustment, activityAlignment, 1.0E-2, 1.0E-2, 1); + + if (search.isTargetAltered()) { + double newAdjustment = search.getTarget()[0]; + Parameters.putTimeSeriesValue(getYear(), newAdjustment, TimeSeriesVariable.UtilityAdjustment); + System.out.println("Utility adjustment for all types was " + newAdjustment); + } + } + + + + public void activityAlignmentSingleMales() { double utilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.UtilityAdjustmentSingleMales); - ActivityAlignment activityAlignmentSingleMales = new ActivityAlignment(persons, benefitUnits, Parameters.getCoeffLabourSupplyUtilityMales(), new String[]{"MaleLeisure"}, Occupancy.Single_Male, utilityAdjustment); - RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentSingleMales, 1.0E-2, 1.0E-2, 0.5); // epsOrdinates and epsFunction determine the stopping condition for the search. + ActivityAlignmentV2 activityAlignmentSingleMales = new ActivityAlignmentV2(benefitUnits, Parameters.getCoeffLabourSupplyUtilityMales(), new String[]{"MaleLeisure"}, Occupancy.Single_Male); + RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentSingleMales, 1.0E-2, 1.0E-2, 10); // epsOrdinates and epsFunction determine the stopping condition for the search. if (search.isTargetAltered()) { Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.UtilityAdjustmentSingleMales); // If adjustment is altered from the initial value, update the map System.out.println("Utility adjustment for single males was " + search.getTarget()[0]); @@ -1864,8 +1523,8 @@ public void activityAlignmentSingleMales() { public void activityAlignmentSingleFemales() { double utilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.UtilityAdjustmentSingleFemales); - ActivityAlignment activityAlignmentSingleFemales = new ActivityAlignment(persons, benefitUnits, Parameters.getCoeffLabourSupplyUtilityFemales(), new String[]{"FemaleLeisure"}, Occupancy.Single_Female, utilityAdjustment); - RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentSingleFemales, 1.0E-2, 1.0E-2, 2); // epsOrdinates and epsFunction determine the stopping condition for the search. + ActivityAlignmentV2 activityAlignmentSingleFemales = new ActivityAlignmentV2(benefitUnits, Parameters.getCoeffLabourSupplyUtilityFemales(), new String[]{"FemaleLeisure"}, Occupancy.Single_Female); + RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentSingleFemales, 1.0E-2, 1.0E-2, 10); // epsOrdinates and epsFunction determine the stopping condition for the search. if (search.isTargetAltered()) { Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.UtilityAdjustmentSingleFemales); // If adjustment is altered from the initial value, update the map System.out.println("Utility adjustment for single females was " + search.getTarget()[0]); @@ -1874,8 +1533,8 @@ public void activityAlignmentSingleFemales() { public void activityAlignmentCouples() { double utilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.UtilityAdjustmentCouples); - ActivityAlignment activityAlignmentCouples = new ActivityAlignment(persons, benefitUnits, Parameters.getCoeffLabourSupplyUtilityCouples(), new String[]{"MaleLeisure","FemaleLeisure"}, Occupancy.Couple, utilityAdjustment); - RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentCouples, 1.0E-2, 1.0E-2, 2); // epsOrdinates and epsFunction determine the stopping condition for the search. + ActivityAlignmentV2 activityAlignmentCouples = new ActivityAlignmentV2(benefitUnits, Parameters.getCoeffLabourSupplyUtilityCouples(), new String[]{"MaleLeisure","FemaleLeisure"}, Occupancy.Couple); + RootSearch search = getRootSearch(utilityAdjustment, activityAlignmentCouples, 1.0E-2, 1.0E-2, 10); // epsOrdinates and epsFunction determine the stopping condition for the search. if (search.isTargetAltered()) { Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.UtilityAdjustmentCouples); // If adjustment is altered from the initial value, update the map System.out.println("Utility adjustment for couples was " + search.getTarget()[0]); @@ -1967,79 +1626,6 @@ public void resample(Person agent) { } - /** - * PROCESS - ALIGN THE SHARE OF EMPLOYED IN THE SIMULATED POPULATION - */ - - private void employmentAlignment() { - - //Create a nested map to store persons by gender and region - LinkedHashMap>> personsByGenderAndRegion; - personsByGenderAndRegion = new LinkedHashMap>>(); - - EnumSet regionEnumSet = null; - if (country.equals(Country.IT)) { - regionEnumSet = EnumSet.of(Region.ITC, Region.ITH, Region.ITI, Region.ITF, Region.ITG); - } else if (country.equals(Country.UK)) { - regionEnumSet = EnumSet.of(Region.UKC, Region.UKD, Region.UKE, Region.UKF, Region.UKG, Region.UKH, Region.UKI, Region.UKJ, Region.UKK, Region.UKL, Region.UKM, Region.UKN); - } - - for (Gender gender : Gender.values()) { - personsByGenderAndRegion.put(gender, new LinkedHashMap>()); - for (Region region : regionEnumSet) { - personsByGenderAndRegion.get(gender).put(region, new LinkedHashSet()); - } - } - - //Iterate over persons and add them to the nested map above - for (Person person : persons) { - if (person.getDag() >= 18 && person.getDag() <= 64) { - personsByGenderAndRegion.get(person.getDgn()).get(person.getRegion()).add(person); - } - } - - //For all gender and region combinations, compare the share of employed persons with the alignment target - for (Gender gender : Gender.values()) { - for (Region region : regionEnumSet) { - double numberEmployed = 0; - Set personsToIterateOver = personsByGenderAndRegion.get(gender).get(region); - - for (Person person : personsToIterateOver) { - numberEmployed += person.getEmployed(); - } - - double sizeSimulatedSet = personsToIterateOver.size(); - - double shareEmployedSimulated = numberEmployed/sizeSimulatedSet; - double shareEmployedTargeted = Parameters.getTimeSeriesValue(year, gender.toString(), region.toString(), TimeSeriesVariable.EmploymentAlignment); - - int targetNumberEmployed = (int) (shareEmployedTargeted*sizeSimulatedSet); - - - //Simulated share of employment exceeds projections => move some individuals at random to non-employment - if ((int) numberEmployed > targetNumberEmployed) { - new ResamplingAlignment().align( - personsToIterateOver, - null, - new AlignmentOutcomeClosure() { - @Override - public boolean getOutcome(Person person) { - return person.getLes_c4().equals(Les_c4.EmployedOrSelfEmployed); - } - - @Override - public void resample(Person person) { - person.setLes_c4(Les_c4.NotEmployed); - person.setLabourSupplyWeekly(Labour.ZERO); - } - }, - targetNumberEmployed); - } - } - } - - } - /** * * PROCESS - ALIGN THE SHARE OF STUDENTS IN THE SIMULATED POPULATION @@ -2047,60 +1633,14 @@ public void resample(Person person) { */ private void inSchoolAlignment() { - int numStudents = 0; - int num16to29 = 0; - ArrayList personsLeavingSchool = new ArrayList(); - for (Person person : persons) { - if (person.getDag() > 15 && person.getDag() < 30) { //Could introduce separate alignment for different age groups, but this is more flexible as it depends on the regression process within the larger alignment target - num16to29++; - if (person.getLes_c4().equals(Les_c4.Student)) { - numStudents++; - } - if (person.isToLeaveSchool()) { //Only those who leave school for the first time have toLeaveSchool set to true - personsLeavingSchool.add(person); - } - } - } - - int targetNumberOfPeopleLeavingSchool = numStudents - (int)( (double)num16to29 * ((Number) Parameters.getStudentShareProjections().getValue(country.toString(), year)).doubleValue() ); - - System.out.println("Number of students < 30 is " + numStudents + " Persons set to leave school " + personsLeavingSchool.size() + " Number of people below 30 " + num16to29 - + " Target number of people leaving school " + targetNumberOfPeopleLeavingSchool); - - if (targetNumberOfPeopleLeavingSchool <= 0) { - for(Person person : personsLeavingSchool) { - person.setToLeaveSchool(false); //Best case scenario is to prevent anyone from leaving school in this year as the target share of students is higher than the number of students. Although we cannot match the target, this is the nearest we can get to it. - if(Parameters.systemOut) { - System.out.println("target number of school leavers is not positive. Force all school leavers to stay at school."); - } - } - } else if (targetNumberOfPeopleLeavingSchool < personsLeavingSchool.size()) { - if(Parameters.systemOut) { - System.out.println("Schooling alignment: target number of students is " + targetNumberOfPeopleLeavingSchool); - } - new ResamplingAlignment().align( - personsLeavingSchool, - null, - new AlignmentOutcomeClosure() { - @Override - public boolean getOutcome(Person agent) { - return agent.isToLeaveSchool(); - } - - @Override - public void resample(Person agent) { - agent.setToLeaveSchool(false); - } - }, - targetNumberOfPeopleLeavingSchool); + InSchoolAlignment inSchoolAlignment = new InSchoolAlignment(persons); + double inSchoolAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.InSchoolAdjustment); + RootSearch search = getRootSearch(inSchoolAdjustment, inSchoolAlignment, 1.0E-2, 1.0E-2, 4); // epsOrdinates and epsFunction determine the stopping condition for the search. For inSchoolAlignment error term is the difference between target and observed share of partnered individuals. - int numPostAlign = 0; - for(Person person : persons) { - if(person.isToLeaveSchool()) { - numPostAlign++; - } - } - System.out.println("Schooling alignment: aligned number of students is " + numPostAlign); + // update and exit + if (search.isTargetAltered()) { + Parameters.putTimeSeriesValue(getYear(), search.getTarget()[0], TimeSeriesVariable.InSchoolAdjustment); // If adjustment is altered from the initial value, update the map + System.out.println("InSchool adjustment value was " + search.getTarget()[0]); } } @@ -2226,9 +1766,9 @@ private void fertilityAlignment() { FertilityAlignment fertilityAlignment = new FertilityAlignment(persons); // define limits of search algorithm - double fertiityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.FertilityAdjustment); - double minVal = Math.max(-4.0, - fertiityAdjustment - 4.0); - double maxVal = Math.min(4.0, - fertiityAdjustment + 4.0); + double fertilityAdjustment = Parameters.getTimeSeriesValue(getYear(), TimeSeriesVariable.FertilityAdjustment); + double minVal = Math.max(-4.0, - fertilityAdjustment - 4.0); + double maxVal = Math.min(4.0, - fertilityAdjustment + 4.0); // run search RootSearch search = getRootSearch(0.0, minVal, maxVal, fertilityAlignment, 5.0E-3, 5.0E-3); // epsOrdinates and epsFunction determine the stopping condition for the search. For partnershipAlignment error term is the difference between target and observed share of partnered individuals. @@ -2544,7 +2084,7 @@ else if (flagSearch1) { // save to processed repository System.out.println("Saving compiled input data for future reference"); - persistProcessed(); + // persistProcessed(); stopwatch.stop(); System.out.println("Time elapsed " + stopwatch.getTime()/1000 + " seconds"); @@ -2972,11 +2512,26 @@ public boolean isAlignFertility() { return alignFertility; } - public void setAlignFertility(boolean alignFertility) { this.alignFertility = alignFertility; } + public boolean isAlignRetirement() { + return alignRetirement; + } + + public boolean isAlignDisability() { + return alignDisability; + } + + public void setAlignDisability(boolean alignDisability) { + this.alignDisability = alignDisability; + } + + public void setAlignRetirement(boolean alignRetirement) { + this.alignRetirement = alignRetirement; + } + public void setSaveImperfectTaxDBMatches(boolean flag) { saveImperfectTaxDBMatches = flag; } @@ -2997,6 +2552,10 @@ public void setAlignInSchool(boolean flag) { alignInSchool = flag; } + public boolean isAlignInSchool() { + return alignInSchool; + } + public void setYear(int year) { this.year = year; } @@ -3074,6 +2633,38 @@ public void setResponsesToRegion(boolean responsesToRegion) { this.responsesToRegion = responsesToRegion; } + public MacroScenarioPopulation getMacroShockPopulation() { + return macroShockPopulation; + } + + public void setMacroShockPopulation(MacroScenarioPopulation macroShockPopulation) { + this.macroShockPopulation = macroShockPopulation; + } + + public MacroScenarioProductivity getMacroShockProductivity() { + return macroShockProductivity; + } + + public void setMacroShockProductivity(MacroScenarioProductivity macroShockProductivity) { + this.macroShockProductivity = macroShockProductivity; + } + + public MacroScenarioGreenPolicy getMacroShockGreenPolicy() { + return macroShockGreenPolicy; + } + + public void setMacroShockGreenPolicy(MacroScenarioGreenPolicy macroShockGreenPolicy) { + this.macroShockGreenPolicy = macroShockGreenPolicy; + } + + public boolean isMacroShocksOn() { + return macroShocksOn; + } + + public void setMacroShocksOn(boolean macroShocksOn) { + this.macroShocksOn = macroShocksOn; + } + public boolean getFlagDefaultToTimeSeriesAverages() { return flagDefaultToTimeSeriesAverages; } public void setFlagDefaultToTimeSeriesAverages(boolean val) { flagDefaultToTimeSeriesAverages = val; } public boolean getResponsesToLowWageOffer() { return responsesToLowWageOffer; } @@ -3219,15 +2810,15 @@ private static void populateTaxdbReferences() { } } MahalanobisDistance mdDualIncome = new MahalanobisDistance(dataDualIncome); - MahalanobisDistance mdChildcare = new MahalanobisDistance(dataChildcare); - MahalanobisDistance mdDualIncomeChildcare = new MahalanobisDistance(dataDualIncomeChildcare); + // MahalanobisDistance mdChildcare = new MahalanobisDistance(dataChildcare); + // MahalanobisDistance mdDualIncomeChildcare = new MahalanobisDistance(dataDualIncomeChildcare); // instantiate Parameters for retrieval Parameters.setTaxdbReferences(taxdbReferences); Parameters.setDonorPool(donorPool); Parameters.setMdDualIncome(mdDualIncome); - Parameters.setMdChildcare(mdChildcare); - Parameters.setMdDualIncomeChildcare(mdDualIncomeChildcare); + // Parameters.setMdChildcare(mdChildcare); + // Parameters.setMdDualIncomeChildcare(mdDualIncomeChildcare); // close database connection txn.commit(); diff --git a/src/main/java/simpaths/model/TaxEvaluation.java b/src/main/java/simpaths/model/TaxEvaluation.java index 439ab4de4..da4a6b83f 100644 --- a/src/main/java/simpaths/model/TaxEvaluation.java +++ b/src/main/java/simpaths/model/TaxEvaluation.java @@ -65,6 +65,7 @@ public TaxEvaluation(int year, int age, int numberMembersOver17, int numberChild } + /** * WORKER METHODS */ diff --git a/src/main/java/simpaths/model/decisions/Axis.java b/src/main/java/simpaths/model/decisions/Axis.java index 676f2beab..64557cf46 100644 --- a/src/main/java/simpaths/model/decisions/Axis.java +++ b/src/main/java/simpaths/model/decisions/Axis.java @@ -18,7 +18,7 @@ public enum Axis { Retirement, Health, Disability, - SocialCareReceiptState, + SocialCareReceipt, SocialCareProvision, Region, Student, diff --git a/src/main/java/simpaths/model/decisions/DecisionParams.java b/src/main/java/simpaths/model/decisions/DecisionParams.java index 81f579029..87394fd9d 100644 --- a/src/main/java/simpaths/model/decisions/DecisionParams.java +++ b/src/main/java/simpaths/model/decisions/DecisionParams.java @@ -13,7 +13,7 @@ public class DecisionParams { // RUNNING OPTIONS public static final boolean PARALLELISE_SOLUTIONS = true; - public static boolean saveGridSlicesToCSV = false; + public static boolean saveGridSlicesToCSV = true; public static boolean saveIntermediateSolutions = false; public static boolean saveImperfectTaxDbMatches = false; @@ -22,7 +22,7 @@ public class DecisionParams { public static final double MIN_FACTOR_PROBABILITY = 0.05; // if FILTER_LOCAL_EXPECTATIONS, omits events with probability less than mean probability multiplied by this threshold public static final boolean SOLVE_FROM_INTERMEDIATE = false; - public static final int SOLVE_FROM_AGE = 74; // if SOLVE_FROM_INTERMEDIATE + public static final int SOLVE_FROM_AGE = 36; // if SOLVE_FROM_INTERMEDIATE // MODEL SETTINGS public static final double GRID_DEFAULT_VALUE = 999.0; @@ -44,7 +44,7 @@ public class DecisionParams { // TIME PARAMETERS public static final double FULLTIME_HOURS_WEEKLY = 35; // hours per week associated with full-time work public static final double PARTTIME_HOURS_WEEKLY = 16; // hours per week associated with part-time work - public static final double MIN_WORK_HOURS_WEEKLY = 5; // minimum hours per week to be considered working + public static final double MIN_WORK_HOURS_WEEKLY = 1; // minimum hours per week to be considered working // DIRECTORIES public static String gridsOutputDirectory; // directory to read/write grids data @@ -65,7 +65,7 @@ public class DecisionParams { public static final double MIN_CONSUMPTION_PER_YEAR = 5 * 52; // minimum feasible consumption per year // LIQUID WEALTH STATE - //public static final int PTS_LIQUID_WEALTH = 26; // number of discrete points used to approximate liquid wealth + //public static final int PTS_LIQUID_WEALTH = 21; // number of discrete points used to approximate liquid wealth public static final int PTS_LIQUID_WEALTH_WKG = 21; public static final int PTS_LIQUID_WEALTH_RTD = 21; public static final double C_LIQUID_WEALTH = 50260.0; // state-space summarised by logarithmic scale: w = exp(x) - c; larger c is closer to arithmetic scale @@ -75,7 +75,7 @@ public class DecisionParams { // FULL-TIME WAGE POTENTIAL STATE public static int maxAgeFlexibleLabourSupply; - //public static final int PTS_WAGE_POTENTIAL = 26; // number of discrete points used to approximate full-time wage potential + //public static final int PTS_WAGE_POTENTIAL = 21; // number of discrete points used to approximate full-time wage potential public static final int PTS_WAGE_POTENTIAL = 21; public static final double MAX_WAGE_PHOUR = 175.0; // maximum per hour public static final double MIN_WAGE_PHOUR = 1.25; // minimum per hour diff --git a/src/main/java/simpaths/model/decisions/DecisionTests.java b/src/main/java/simpaths/model/decisions/DecisionTests.java index df293f171..c62f27060 100644 --- a/src/main/java/simpaths/model/decisions/DecisionTests.java +++ b/src/main/java/simpaths/model/decisions/DecisionTests.java @@ -6,11 +6,8 @@ import com.opencsv.exceptions.CsvDataTypeMismatchException; import com.opencsv.exceptions.CsvRequiredFieldEmptyException; import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVPrinter; -import org.apache.commons.csv.CSVRecord; import simpaths.data.Parameters; -import simpaths.model.taxes.Matches; import java.io.*; import java.nio.file.Files; diff --git a/src/main/java/simpaths/model/decisions/Expectations.java b/src/main/java/simpaths/model/decisions/Expectations.java index 1827fe6e1..949e11f02 100644 --- a/src/main/java/simpaths/model/decisions/Expectations.java +++ b/src/main/java/simpaths/model/decisions/Expectations.java @@ -1,18 +1,17 @@ package simpaths.model.decisions; -import java.security.InvalidParameterException; -import java.util.*; - import simpaths.data.ManagerRegressions; import simpaths.data.Parameters; import simpaths.data.RegressionName; -import simpaths.model.enums.*; import simpaths.model.BenefitUnit; import simpaths.model.Person; import simpaths.model.TaxEvaluation; +import simpaths.model.enums.*; import simpaths.model.taxes.Match; import simpaths.model.taxes.Matches; +import java.security.InvalidParameterException; + import static simpaths.data.Parameters.asinh; @@ -233,10 +232,6 @@ public Expectations(Expectations invariantExpectations) { */ public void updateForDiscreteControls(double emp1Pr, double emp2Pr) { - // working variables - int stateIndexNextPeriod, stateIndexCurrPeriod; - - //******************************************************** // update current period variables for discrete decisions //******************************************************** @@ -419,7 +414,7 @@ public void updateForDiscreteControls(double emp1Pr, double emp2Pr) { // cohabitation (1 = cohabiting) if (ageYearsNextPeriod <= DecisionParams.MAX_AGE_COHABITATION) { - futures.updateCohabitation(); + futures.updateCohabitation(); } // dependent children diff --git a/src/main/java/simpaths/model/decisions/ExpectationsFactory.java b/src/main/java/simpaths/model/decisions/ExpectationsFactory.java index ae145c881..bee6881ce 100644 --- a/src/main/java/simpaths/model/decisions/ExpectationsFactory.java +++ b/src/main/java/simpaths/model/decisions/ExpectationsFactory.java @@ -3,7 +3,6 @@ import simpaths.data.ManagerRegressions; import simpaths.data.Parameters; import simpaths.data.RegressionName; -import simpaths.data.RegressionType; import simpaths.model.Person; import simpaths.model.enums.Dcpst; import simpaths.model.enums.Gender; @@ -109,13 +108,13 @@ public void updateStudent() { int numberExpectedInitial = numberExpected; boolean flagEval; LocalExpectations lexpect = new LocalExpectations(); - lexpect.evaluate(personProxyNextPeriod, RegressionName.EducationE1a); + lexpect.evaluateDiscrete(personProxyNextPeriod, RegressionName.EducationE1a); for (int ii=0; ii probsCareFrom = Parameters.getRegSocialCareMarketS2c().getProbabilites(personProxyNextPeriod, Person.DoublesVariables.class); + Map probsCareFrom = Parameters.getRegSocialCareMarketS2c().getProbabilities(personProxyNextPeriod, Person.DoublesVariables.class); // compile and package outputs int ii = 0; @@ -403,7 +402,7 @@ private boolean updatePersonNextPeriod(int ii) { if (flagChange) flagEval = true; } if (flagSocialCareReceiptVaries) { - flagChange = updatePersonNextPeriod(anticipated[ii], Axis.SocialCareReceiptState); + flagChange = updatePersonNextPeriod(anticipated[ii], Axis.SocialCareReceipt); if (flagChange) flagEval = true; } if (flagSocialCareProvisionVaries) { @@ -440,7 +439,7 @@ private boolean updatePersonNextPeriod(States states, Axis axis) { } else if (Axis.Disability.equals(axis)) { val0 = personProxyNextPeriod.getDlltsd(); val1 = states.getDlltsd(); - } else if (Axis.SocialCareReceiptState.equals(axis)) { + } else if (Axis.SocialCareReceipt.equals(axis)) { val0 = personProxyNextPeriod.getSocialCareReceipt(); val1 = states.getSocialCareReceiptCode(); } else if (Axis.SocialCareProvision.equals(axis)) { @@ -475,7 +474,7 @@ private boolean updatePersonNextPeriod(States states, Axis axis) { personProxyNextPeriod.setDhe(states.getHealthCode()); } else if (Axis.Disability.equals(axis)) { personProxyNextPeriod.setDlltsd(states.getDlltsd()); - } else if (Axis.SocialCareReceiptState.equals(axis)) { + } else if (Axis.SocialCareReceipt.equals(axis)) { personProxyNextPeriod.setSocialCareReceipt(states.getSocialCareReceiptCode()); } else if (Axis.SocialCareProvision.equals(axis)) { personProxyNextPeriod.setSocialCareProvision(states.getSocialCareProvisionCode()); diff --git a/src/main/java/simpaths/model/decisions/Grid.java b/src/main/java/simpaths/model/decisions/Grid.java index a16336dfe..66faa968b 100644 --- a/src/main/java/simpaths/model/decisions/Grid.java +++ b/src/main/java/simpaths/model/decisions/Grid.java @@ -1,7 +1,6 @@ package simpaths.model.decisions; import java.security.InvalidParameterException; -import simpaths.model.decisions.DecisionParams; /** diff --git a/src/main/java/simpaths/model/decisions/GridScale.java b/src/main/java/simpaths/model/decisions/GridScale.java index 9a9c2e9c2..057beeea1 100644 --- a/src/main/java/simpaths/model/decisions/GridScale.java +++ b/src/main/java/simpaths/model/decisions/GridScale.java @@ -499,10 +499,10 @@ public int getIndex(Enum axisID, int ageYears, int birthAge) { // social care receipt if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) { - if (axisID==Axis.SocialCareReceiptState) return dimIndex; + if (axisID==Axis.SocialCareReceipt) return dimIndex; dimIndex++; } else { - if (axisID==Axis.SocialCareReceiptState) return -1; + if (axisID==Axis.SocialCareReceipt) return -1; } // social care provision diff --git a/src/main/java/simpaths/model/decisions/LocalExpectations.java b/src/main/java/simpaths/model/decisions/LocalExpectations.java index 9e3e4f743..849a326a8 100644 --- a/src/main/java/simpaths/model/decisions/LocalExpectations.java +++ b/src/main/java/simpaths/model/decisions/LocalExpectations.java @@ -1,14 +1,12 @@ package simpaths.model.decisions; -import microsim.statistics.IDoubleSource; +import microsim.statistics.regression.IntegerValuedEnum; +import microsim.statistics.regression.RegressionType; import simpaths.data.ManagerRegressions; -import simpaths.data.Parameters; import simpaths.data.RegressionName; -import simpaths.data.RegressionType; import simpaths.model.Person; -import simpaths.model.enums.IntegerValuedEnum; -import simpaths.model.enums.TimeSeriesVariable; +import simpaths.model.enums.ReversedIndicator; import java.util.Map; @@ -61,50 +59,22 @@ public void screenAndAssign(double[] probs, double[] vals) { } } - public void evaluate(Person person, RegressionName regression) { - - if (RegressionType.StandardProbit.equals(regression.getType()) || RegressionType.AdjustedStandardProbit.equals(regression.getType())) { - // binomial regression - evaluateIndicator(person, regression); - } else if (RegressionType.ReversedProbit.equals(regression.getType())) { - evaluateIndicator(person, regression, 0.0); - } else if (RegressionType.MultinomialLogit.equals(regression.getType()) || RegressionType.OrderedProbit.equals(regression.getType())) { - // multinomial regression - evaluateMultinomial(person, regression); - } else { - throw new RuntimeException("unexpected regression specification submitted for evaluation of local expectations"); - } - } - public void assignValue(double value) { probabilities = new double[] {1.0}; values = new double[] {value}; } - public void evaluateIndicator(Person person, RegressionName regression) { - evaluateIndicator(person, regression, 1.0); - } - - public void evaluateIndicator(Person person, RegressionName regression, Double valueTrue) { + public void evaluateLabelledIndicator(Person person, RegressionName regression, Double valueTrue) { double[] probs, vals; - double score = ManagerRegressions.getScore(person, regression); - double adj = 0.0; - if (RegressionType.AdjustedStandardProbit.equals(regression.getType())) { - adj = Parameters.getTimeSeriesValue(person.getYear(), TimeSeriesVariable.FertilityAdjustment); - } - - double prob = ManagerRegressions.getProbability(score + adj, regression); + double prob = ManagerRegressions.getProbability(person, regression); probs = new double[] {1.0-prob, prob}; - if (Math.abs(valueTrue)<1.0E-5) - vals = new double[] {1.0, 0.0}; - else - vals = new double[] {0.0, valueTrue}; + vals = new double[] {0.0, valueTrue}; screenAndAssign(probs, vals); } - private & IntegerValuedEnum> void evaluateMultinomial(Person person, RegressionName regression) { + public & IntegerValuedEnum> void evaluateDiscrete(Person person, RegressionName regression) { double[] probs, vals; - Map probsMap = ManagerRegressions.getMultinomialProbabilities(person, regression); + Map probsMap = ManagerRegressions.getProbabilities(person, regression); int nn = probsMap.size(); if (nn<2) throw new RuntimeException("call to evaluate multinomial probabilities returned fewer than 2 results"); @@ -112,8 +82,14 @@ private & IntegerValuedEnum> void evaluateMultinomial(Person probs = new double[nn]; int ii = 0; for (E key : probsMap.keySet()) { - probs[ii] = probsMap.get(key); - vals[ii] = (double)key.getValue(); + double prob = probsMap.get(key); + if (prob<0.0 && !RegressionType.GenOrderedProbit.equals(regression.getType()) && !RegressionType.GenOrderedLogit.equals(regression.getType())) + throw new RuntimeException("negative probability evaluated for local expectations"); + probs[ii] = Math.max(0.0,prob); + if (key instanceof ReversedIndicator) + vals[ii] = 1.0 - (double)key.getValue(); + else + vals[ii] = (double)key.getValue(); ii++; } screenAndAssign(probs, vals); diff --git a/src/main/java/simpaths/model/decisions/ManagerFileGrids.java b/src/main/java/simpaths/model/decisions/ManagerFileGrids.java index 51b21188e..525d9288e 100644 --- a/src/main/java/simpaths/model/decisions/ManagerFileGrids.java +++ b/src/main/java/simpaths/model/decisions/ManagerFileGrids.java @@ -4,7 +4,10 @@ import org.apache.commons.csv.CSVPrinter; import simpaths.data.Parameters; -import java.io.*; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; @@ -166,25 +169,31 @@ public static void formattedWrite(Grids grids, int aa) { WriteGridsBean bean = new WriteGridsBean(); // populate with state combination - bean.setCohabitation(currentStates.getCohabitationIndex()); + bean.setLiquidWealth(currentStates.getLiquidWealth()); + bean.setWagePotentialperHour(currentStates.getFullTimeHourlyEarningsPotential()); + bean.setPensionIncomePerYear(currentStates.getPensionPerYear()); + bean.setBirthYear(currentStates.getBirthYear()); + bean.setWageOffer1(currentStates.getWageOffer1()); + //bean.setWageOffer2(currentStates.getWageOffer2()); + bean.setRetirement(currentStates.getRetirement()); + bean.setHealth(currentStates.getHealthVal()); + bean.setDisability(currentStates.getDisability()); + bean.setSocialCareReceipt(currentStates.getSocialCareReceipt()); + bean.setSocialCareProvision(currentStates.getSocialCareProvision()); + bean.setRegion(currentStates.getRegion()); + bean.setStudent(currentStates.getStudent()); + bean.setEducation(currentStates.getEducation()); bean.setNk0(currentStates.getChildrenByBirthIndex(0)); bean.setNk1(currentStates.getChildrenByBirthIndex(1)); bean.setNk2(currentStates.getChildrenByBirthIndex(2)); - bean.setBirthYear(currentStates.getBirthYear()); + bean.setCohabitation(currentStates.getCohabitationIndex()); bean.setGender(currentStates.getGender()); - bean.setEducation(currentStates.getEducation()); - bean.setStudent(currentStates.getStudent()); - bean.setHealth(currentStates.getHealthVal()); - bean.setWageOffer(currentStates.getWageOffer()); - bean.setLiquidWealth(currentStates.getLiquidWealth()); - bean.setWagePotentialperHour(currentStates.getFullTimeHourlyEarningsPotential()); - bean.setPensionIncomePerYear(currentStates.getPensionPerYear()); // populate with grid solutions - bean.setValueFunction(grids.getValueFunction(currentStates)); bean.setConsumptionShare(grids.getConsumptionShare(currentStates)); bean.setEmployment1(grids.getEmployment1(currentStates)); bean.setEmployment2(grids.getEmployment2(currentStates)); + bean.setValueFunction(grids.getValueFunction(currentStates)); // add to list beans.add(bean); @@ -195,8 +204,9 @@ public static void formattedWrite(Grids grids, int aa) { File dir = new File(DecisionParams.gridsOutputDirectory); if (!dir.exists()) dir.mkdir(); String filePath = DecisionParams.gridsOutputDirectory + File.separator + "grid_age_" + ageYears + ".csv"; - String[] HEADERS = {"gender", "birthyear", "education", "student", "married", "children0", "children1", "children2", "health", "wealth", "wageperhour", "pensionperyear", - "valuefunction", "consumptionshare", "employment1", "employment2"}; + String[] HEADERS = {"wealth", "wageperhour", "pensionperyear", "birthyear", "wageoffer1", "retirement", "health", "disability", + "socialcarereceipt", "socialcareprovision", "region", "student", "education", "children0", "children1", "children2", + "married", "gender", "consumptionshare", "employment1", "employment2", "valuefunction"}; try { BufferedWriter writer = Files.newBufferedWriter(Paths.get(filePath)); CSVFormat csvFormat = CSVFormat.DEFAULT.builder().setHeader(HEADERS).build(); @@ -204,23 +214,28 @@ public static void formattedWrite(Grids grids, int aa) { for (WriteGridsBean bean : beans) { List record = new ArrayList<>(); - record.add(bean.getGenderString()); + record.add(bean.getLiquidWealthString()); + record.add(bean.getWagePotentialperHourString()); + record.add(bean.getPensionIncomePerYearString()); record.add(bean.getBirthYearString()); - record.add(bean.getEducationString()); + record.add(bean.getWageOffer1String()); + record.add(bean.getRetirementString()); + record.add(bean.getHealthString()); + record.add(bean.getDisabilityString()); + record.add(bean.getSocialCareReceiptString()); + record.add(bean.getSocialCareProvisionString()); + record.add(bean.getRegionString()); record.add(bean.getStudentString()); - record.add(bean.getCohabitationString()); + record.add(bean.getEducationString()); record.add(bean.getNk0String()); record.add(bean.getNk1String()); record.add(bean.getNk2String()); - record.add(bean.getHealthString()); - record.add(bean.getWageOfferString()); - record.add(bean.getLiquidWealthString()); - record.add(bean.getWagePotentialperHourString()); - record.add(bean.getPensionIncomePerYearString()); - record.add(bean.getValueFunctionString()); + record.add(bean.getCohabitationString()); + record.add(bean.getGenderString()); record.add(bean.getConsumptionShareString()); record.add(bean.getEmployment1String()); record.add(bean.getEmployment2String()); + record.add(bean.getValueFunctionString()); printer.printRecord(record); } diff --git a/src/main/java/simpaths/model/decisions/ManagerPopulateGrids.java b/src/main/java/simpaths/model/decisions/ManagerPopulateGrids.java index a91695781..cd4bdcdf6 100644 --- a/src/main/java/simpaths/model/decisions/ManagerPopulateGrids.java +++ b/src/main/java/simpaths/model/decisions/ManagerPopulateGrids.java @@ -1,11 +1,11 @@ package simpaths.model.decisions; +import simpaths.model.SimPathsModel; + import java.time.Duration; import java.time.Instant; -import simpaths.model.SimPathsModel; - /** * CLASS TO MANAGE IDENTIFICATION OF LOOK-UP TABLE FOR INTERTEMPORAL OPTIMISATION DECISIONS diff --git a/src/main/java/simpaths/model/decisions/States.java b/src/main/java/simpaths/model/decisions/States.java index 97661271e..c8d21705c 100644 --- a/src/main/java/simpaths/model/decisions/States.java +++ b/src/main/java/simpaths/model/decisions/States.java @@ -1,11 +1,11 @@ package simpaths.model.decisions; -import java.security.InvalidParameterException; - import simpaths.data.Parameters; +import simpaths.model.BenefitUnit; import simpaths.model.Person; import simpaths.model.enums.*; -import simpaths.model.BenefitUnit; + +import java.security.InvalidParameterException; /** @@ -104,7 +104,7 @@ public States(BenefitUnit benefitUnit, GridScale scale) { // social care receipt if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) - populate(Axis.SocialCareReceiptState, (double)refPerson.getSocialCareReceiptState().getValue()); + populate(Axis.SocialCareReceipt, (double)refPerson.getSocialCareReceiptState().getValue()); // social care provision if (Parameters.flagSocialCare) @@ -324,7 +324,7 @@ boolean checkOuterStateCombination() { boolean loopConsider = true; // check wage offer - int wageOffer = getWageOffer(); + int wageOffer = getWageOffer1(); if (wageOffer == 0) { // skip if no wage offer is received, as numerical solution for this state combination is identical to @@ -391,7 +391,7 @@ public double getPensionPerYear() { * METHOD TO EXTRACT WAGE OFFER STATE FROM STATES ARRAY * @return the wage offer state if during working lifetime, and -1 otherwise */ - int getWageOffer() { + int getWageOffer1() { int wageOffer; if (ageYears <= DecisionParams.maxAgeFlexibleLabourSupply && DecisionParams.flagLowWageOffer1) { wageOffer = (int) Math.round(states[scale.getIndex(Axis.WageOffer1, ageYears)]); @@ -606,7 +606,10 @@ int getBirthYear() { * METHOD TO RETURN GEOGRAPHIC REGION IMPLIED BY STATE COMBINATION * @return integer */ - int getRegion() { return (int)states[scale.getIndex(Axis.Region, ageYears)]; } + int getRegion() { + int index = scale.getIndex(Axis.Region, ageYears); + return (index<0) ? 0 : (int)states[index]; + } /** * METHOD TO RETURN DISABILITY STATUS IMPLIED BY STATE COMBINATION @@ -624,9 +627,9 @@ int getDisability() { * METHOD TO RETURN SOCIAL CARE RECEIPT * @return integer (0 none needed, 1 no formal (needed but not received or only informal), 2 formal and informal, 3 only formal */ - int getSocialCareReceiptState() { + int getSocialCareReceipt() { if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) { - return (int)states[scale.getIndex(Axis.SocialCareReceiptState, ageYears)]; + return (int)states[scale.getIndex(Axis.SocialCareReceipt, ageYears)]; } else { return 0; } @@ -640,7 +643,7 @@ public boolean getPrincipalEligibleForWork() { if (!Parameters.flagSuppressSocialCareCosts) { if (getDisability()==1) return false; - if (getSocialCareReceiptState()>0) + if (getSocialCareReceipt()>0) return false; } return true; @@ -890,7 +893,7 @@ Dhe getHealthCode() { SocialCareReceiptState getSocialCareReceiptStateCode() { SocialCareReceiptState code; if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) - code = SocialCareReceiptState.getCode(getVal(Axis.SocialCareReceiptState)); + code = SocialCareReceiptState.getCode(getVal(Axis.SocialCareReceipt)); else code = SocialCareReceiptState.NoneNeeded; return code; @@ -902,7 +905,7 @@ SocialCareReceiptState getSocialCareReceiptStateCode() { SocialCareReceipt getSocialCareReceiptCode() { SocialCareReceipt code; if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) - code = SocialCareReceipt.getCode(getVal(Axis.SocialCareReceiptState)); + code = SocialCareReceipt.getCode(getVal(Axis.SocialCareReceipt)); else code = SocialCareReceipt.None; return code; @@ -1034,7 +1037,7 @@ public void systemReportError(long errorIndex) { // social care receipt if (Parameters.flagSocialCare && ageYears >= DecisionParams.minAgeReceiveFormalCare) { - stateIndex = scale.getIndex(Axis.SocialCareReceiptState, ageYears); + stateIndex = scale.getIndex(Axis.SocialCareReceipt, ageYears); printOutOfBounds(stateIndex); msg = "social care receipt: " + String.format(fmtIndicator,states[stateIndex]); System.out.println(msg); diff --git a/src/main/java/simpaths/model/decisions/WriteGridsBean.java b/src/main/java/simpaths/model/decisions/WriteGridsBean.java index 3f8e42c36..6947d47d4 100644 --- a/src/main/java/simpaths/model/decisions/WriteGridsBean.java +++ b/src/main/java/simpaths/model/decisions/WriteGridsBean.java @@ -12,19 +12,25 @@ public class WriteGridsBean { * ATTRIBUTES */ //@CsvBindByName(column = "birthyear") + private double liquidWealth; + private double wagePotentialperHour; + private double pensionIncomePerYear; private int birthYear; - private int gender; + private int wageOffer1; + private int wageOffer2; + private int retirement; + private int health; + private int disability; + private int socialCareReceipt; + private int socialCareProvision; + private int region; private int student; private int education; - private int health; - private int cohabitation; - private int wageOffer; private int nk0; private int nk1; private int nk2; - private double liquidWealth; - private double wagePotentialperHour; - private double pensionIncomePerYear; + private int cohabitation; + private int gender; private double consumptionShare; private double employment1; private double employment2; @@ -39,141 +45,112 @@ public WriteGridsBean(){} /** * SETTERS */ + public void setLiquidWealth(double liquidWealth) { + this.liquidWealth = liquidWealth; + } + public void setWagePotentialperHour(double wagePotentialperHour) {this.wagePotentialperHour = wagePotentialperHour;} + public void setPensionIncomePerYear(double pensionIncomePerYear) {this.pensionIncomePerYear = pensionIncomePerYear;} public void setBirthYear(int birthYear) { this.birthYear = birthYear; } - - public void setGender(int gender) { - this.gender = gender; + public void setWageOffer1(int wageOffer1) {this.wageOffer1 = wageOffer1;} + public void setWageOffer2(int wageOffer2) {this.wageOffer2 = wageOffer2;} + public void setRetirement(int retirement) {this.retirement = retirement;} + public void setHealth(int health) { + this.health = health; } - + public void setDisability(int disability) {this.disability = disability;} + public void setSocialCareReceipt(int socialCareReceipt) {this.socialCareReceipt = socialCareReceipt;} + public void setSocialCareProvision(int socialCareProvision) {this.socialCareProvision = socialCareProvision;} + public void setRegion(int region) {this.region = region;} public void setStudent(int student) { this.student = student; } - public void setEducation(int education) { this.education = education; } - - public void setHealth(int health) { - this.health = health; - } - - public void setCohabitation(int cohabitation) { - this.cohabitation = cohabitation; - } - - public void setWageOffer(int wageOffer) { - this.wageOffer = wageOffer; - } - - public void setNk0(int nk0) { - this.nk0 = nk0; - } - + public void setNk0(int nk0) {this.nk0 = nk0;} public void setNk1(int nk1) { this.nk1 = nk1; } - public void setNk2(int nk2) { this.nk2 = nk2; } - - public void setLiquidWealth(double liquidWealth) { - this.liquidWealth = liquidWealth; - } - - public void setWagePotentialperHour(double wagePotentialperHour) { - this.wagePotentialperHour = wagePotentialperHour; - } - - public void setPensionIncomePerYear(double pensionIncomePerYear) { - this.pensionIncomePerYear = pensionIncomePerYear; + public void setCohabitation(int cohabitation) {this.cohabitation = cohabitation;} + public void setGender(int gender) { + this.gender = gender; } - public void setConsumptionShare(double consumptionShare) { this.consumptionShare = consumptionShare; } - public void setEmployment1(double employment1) { this.employment1 = employment1; } - public void setEmployment2(double employment2) { this.employment2 = employment2; } - public void setValueFunction(double valueFunction) { this.valueFunction = valueFunction; } + /** * GETTERS */ + public double getLiquidWealth() { + return liquidWealth; + } + public double getWagePotentialperHour() { + return wagePotentialperHour; + } + public double getPensionIncomePerYear() { + return pensionIncomePerYear; + } public int getBirthYear() { return birthYear; } - - public int getGender() { - return gender; + public int getWageOffer1() { + return wageOffer1; } - + public int getWageOffer2() {return wageOffer2;} + public int getRetirement() {return retirement;} + public int getHealth() { + return health; + } + public int getDisability() {return disability;} + public int getSocialCareReceipt() {return socialCareReceipt;} + public int getSocialCareProvision() {return socialCareProvision;} + public int getRegion() {return region;} public int getStudent() { return student; } - public int getEducation() { return education; } - - public int getHealth() { - return health; - } - - public int getCohabitation() { - return cohabitation; - } - - public int getWageOffer() { - return wageOffer; - } - public int getNk0() { return nk0; } - public int getNk1() { return nk1; } - public int getNk2() { return nk2; } - - public double getLiquidWealth() { - return liquidWealth; - } - - public double getWagePotentialperHour() { - return wagePotentialperHour; + public int getCohabitation() { + return cohabitation; } - - public double getPensionIncomePerYear() { - return pensionIncomePerYear; + public int getGender() { + return gender; } - public double getConsumptionShare() { return consumptionShare; } - public double getEmployment1() { return employment1; } - public double getEmployment2() { return employment2; } - public double getValueFunction() { return valueFunction; } @@ -182,12 +159,8 @@ public double getValueFunction() { /** * STRING GETTERS */ - - public String getEmployment1String() { - return Double.toString(employment1); - } - public String getEmployment2String() { - return Double.toString(employment2); + public String getLiquidWealthString() { + return Double.toString(liquidWealth); } public String getWagePotentialperHourString() { return Double.toString(wagePotentialperHour); @@ -195,29 +168,32 @@ public String getWagePotentialperHourString() { public String getPensionIncomePerYearString() { return Double.toString(pensionIncomePerYear); } - public String getEducationString() { - return String.valueOf(education); + public String getBirthYearString() { + return String.valueOf(birthYear); } - public String getStudentString() { - return String.valueOf(student); + public String getWageOffer1String() { + return String.valueOf(wageOffer1); } - public String getHealthString() { - return String.valueOf(health); + public String getWageOffer2String() { + return String.valueOf(wageOffer2); } - public String getValueFunctionString() { - return Double.toString(valueFunction); + public String getRetirementString() { + return String.valueOf(retirement); } - public String getConsumptionShareString() { - return Double.toString(consumptionShare); + public String getHealthString() { + return String.valueOf(health); } - public String getLiquidWealthString() { - return Double.toString(liquidWealth); + public String getDisabilityString() { + return String.valueOf(disability); } - public String getCohabitationString() { - return String.valueOf(cohabitation); + public String getSocialCareReceiptString() {return String.valueOf(socialCareReceipt);} + public String getSocialCareProvisionString() {return String.valueOf(socialCareProvision);} + public String getRegionString() {return String.valueOf(region);} + public String getStudentString() { + return String.valueOf(student); } - public String getWageOfferString() { - return String.valueOf(wageOffer); + public String getEducationString() { + return String.valueOf(education); } public String getNk0String() { return String.valueOf(nk0); @@ -228,10 +204,22 @@ public String getNk1String() { public String getNk2String() { return String.valueOf(nk2); } + public String getCohabitationString() { + return String.valueOf(cohabitation); + } public String getGenderString() { return String.valueOf(gender); } - public String getBirthYearString() { - return String.valueOf(birthYear); + public String getConsumptionShareString() { + return Double.toString(consumptionShare); + } + public String getEmployment1String() { + return Double.toString(employment1); + } + public String getEmployment2String() { + return Double.toString(employment2); + } + public String getValueFunctionString() { + return Double.toString(valueFunction); } } diff --git a/src/main/java/simpaths/model/enums/AlignmentVariable.java b/src/main/java/simpaths/model/enums/AlignmentVariable.java index e5120a2c4..e02087866 100644 --- a/src/main/java/simpaths/model/enums/AlignmentVariable.java +++ b/src/main/java/simpaths/model/enums/AlignmentVariable.java @@ -3,4 +3,6 @@ public enum AlignmentVariable { PartnershipAlignment, FertilityAlignment, + RetirementAlignment, + DisabilityAlignment, } diff --git a/src/main/java/simpaths/model/enums/Country.java b/src/main/java/simpaths/model/enums/Country.java index 91551afb0..1df65a38d 100644 --- a/src/main/java/simpaths/model/enums/Country.java +++ b/src/main/java/simpaths/model/enums/Country.java @@ -2,8 +2,7 @@ public enum Country { - IT("Italy", 9), //Italy - UK("United Kingdom", 15); //United Kingdom of Great Britain and Northern Ireland + IT("Italy", 9); // Poland //EUROMOD country codes for all EU countries // Country dct diff --git a/src/main/java/simpaths/model/enums/Dhe.java b/src/main/java/simpaths/model/enums/Dhe.java index 840427d69..fc53fe70c 100644 --- a/src/main/java/simpaths/model/enums/Dhe.java +++ b/src/main/java/simpaths/model/enums/Dhe.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum Dhe implements IntegerValuedEnum { Poor(1), Fair(2), diff --git a/src/main/java/simpaths/model/enums/Education.java b/src/main/java/simpaths/model/enums/Education.java index 0a38f63b7..a51597d94 100644 --- a/src/main/java/simpaths/model/enums/Education.java +++ b/src/main/java/simpaths/model/enums/Education.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum Education implements IntegerValuedEnum { Low(0), diff --git a/src/main/java/simpaths/model/enums/Indicator.java b/src/main/java/simpaths/model/enums/Indicator.java index afc4532ee..75e0fcc0b 100644 --- a/src/main/java/simpaths/model/enums/Indicator.java +++ b/src/main/java/simpaths/model/enums/Indicator.java @@ -1,9 +1,17 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + /* - * The Indicator class is for use with regressions using dummy variables - boolean-like variables that take the value of either 0 or 1, depending on false or true respectively. + * The Indicator class is for use with regressions using dummy variables - boolean-like variables that take the value of either 0 or 1, depending on false or true respectively. */ -public enum Indicator { - False, //Ordinal value 0 - True; //Ordinal value 1 +public enum Indicator implements IntegerValuedEnum { + False(0), + True(1); + + private final int value; + Indicator(int val) { value = val; } + + @Override + public int getValue() {return value;} } diff --git a/src/main/java/simpaths/model/enums/Labour.java b/src/main/java/simpaths/model/enums/Labour.java index 120840c0a..9ad04683f 100644 --- a/src/main/java/simpaths/model/enums/Labour.java +++ b/src/main/java/simpaths/model/enums/Labour.java @@ -1,93 +1,76 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; import simpaths.data.Parameters; import simpaths.model.Person; -/** - * An enumeration representing different categories of weekly labour supply (work hours) provided by persons. - */ - public enum Labour implements IntegerValuedEnum { - //Represents hours of work per week that a Person will supply to firms - ZERO(0, 0, 5), // Note: ZERO always returns 0 continuous hours but maxBound is specified as 5 here to remain consistent with the discretization used in the data - TEN(10, 6, 15), - TWENTY(20, 16, 25), - THIRTY(30, 26, 35), - FORTY(40, 36, Parameters.MAX_LABOUR_HOURS_IN_WEEK); + ZERO(0, 0, 0, 0, 0), // 0 hours for both genders + + // Female categories Male categories + CATEGORY_1(1, 1, 29, 1, 35), // [1-29] vs [1-35] + CATEGORY_2(2, 30, 35, 36, 39), // [30-35] vs [36-39] + CATEGORY_3(3, 36, 39, 40, 49), // [36-39] vs [40-49] + CATEGORY_4(4, 40, 55, 50, 65); // [40+] vs [50+] + + private final int categoryId; + private final int femaleMin, femaleMax; + private final int maleMin, maleMax; - private final int hours, minBound, maxBound; - Labour(int hours, int minBound, int maxBound) { - this.hours = hours; - this.minBound = minBound; - this.maxBound = maxBound; + Labour(int categoryId, int femaleMin, int femaleMax, int maleMin, int maleMax) { + this.categoryId = categoryId; + this.femaleMin = femaleMin; + this.femaleMax = femaleMax; + this.maleMin = maleMin; + this.maleMax = maleMax; } @Override - public int getValue() {return hours;} + public int getValue() { + return categoryId; // Now returns category ID instead of hours + } + + // Gender-aware conversion methods + public static Labour convertHoursToLabour(double hoursWorked, Gender gender) { + if (hoursWorked <= 0) return ZERO; - /** - * Converts hours worked (int) to the corresponding labour category. - * - * @param hoursWorked The hours worked. - * @return The labour category. - */ - public static Labour convertHoursToLabour(int hoursWorked) { - return convertHoursToLabourInternal(hoursWorked); + return switch (gender) { + case Female -> convertFemaleHours(hoursWorked); + default -> convertMaleHours(hoursWorked); + }; } - /** - * Converts hours worked (double) to the corresponding labour category. - * - * @param hoursWorked The hours worked. - * @return The labour category. - */ - public static Labour convertHoursToLabour(double hoursWorked) { - return convertHoursToLabourInternal((int) hoursWorked); + private static Labour convertFemaleHours(double hours) { + if (hours <= 29) return CATEGORY_1; + else if (hours <= 35) return CATEGORY_2; + else if (hours <= 39) return CATEGORY_3; + else return CATEGORY_4; } - private static Labour convertHoursToLabourInternal(int hoursWorked) { - if (hoursWorked <= 5) { - return Labour.ZERO; - } else if (hoursWorked <= 15) { - return Labour.TEN; - } else if (hoursWorked <= 25) { - return Labour.TWENTY; - } else if (hoursWorked <= 35) { - return Labour.THIRTY; - } else { - return Labour.FORTY; - } + private static Labour convertMaleHours(double hours) { + if (hours <= 35) return CATEGORY_1; + else if (hours <= 39) return CATEGORY_2; + else if (hours <= 49) return CATEGORY_3; + else return CATEGORY_4; } - // - /** - * Gets the hours of work based on the labour category and the person's draw from the uniform distribution. - * A switch in Parameters class indicates if discretized or continuous hours should be used. - * If discretized hours are used, returns number of hours as specified by the hours variable. - * If continuous hours are used, returns continuous hours based on person's draw from the uniform distribution and minimum and maximum hours possible in each category, defined by minBound and maxBound. - * Note: ZERO category always returns 0 hours of work, irrespective of whether discretized or continuous hours are requested, and irrespective of min and max bound for the ZERO category. - * - * @param person The person for whom the hours are calculated. - * @return The calculated hours of work. - */ public int getHours(Person person) { - // There were some cases in BenefitUnit where person can be null but hours of work still needed to be obtained where individual is a single adult and labour key composed of two values needs to be defined. - // I replaced that with a 0. value, instead of converting a ZERO labour key to hours, so person should never be null. - // However, added a check for null persons which should result in a default number of hours returned in such cases. - if (this != Labour.ZERO && Parameters.USE_CONTINUOUS_LABOUR_SUPPLY_HOURS && person != null) { + if (this == ZERO) return 0; - // Verify that person's draw is not null. If null, draw a value first. - double personDrawnValue = person.getLabourSupplySingleDraw(); + Gender gender = person.getDgn(); + if (Parameters.USE_CONTINUOUS_LABOUR_SUPPLY_HOURS && person != null) { - // Continuous hours are based on person's randomly drawn value. This can be considered person's "type", for example, a person always works hours in the bottom 10% of a (uniformly distributed) labour supply bracket. - int hours = (int) Math.round(personDrawnValue * (maxBound - minBound) + minBound); - return hours; + int min = (gender == Gender.Female) ? femaleMin : maleMin; + int max = (gender == Gender.Female) ? femaleMax : maleMax; + double draw = person.getLabourSupplySingleDraw(); + return (int) Math.round(draw * (max - min) + min); } else { - return hours; + // Return midpoint for discrete mode + return (gender == Gender.Female) ? + (femaleMin + femaleMax) / 2 : + (maleMin + maleMax) / 2; } } - } - diff --git a/src/main/java/simpaths/model/enums/Les_transitions_E1.java b/src/main/java/simpaths/model/enums/Les_transitions_E1.java index ce10ee885..2b08b45ab 100644 --- a/src/main/java/simpaths/model/enums/Les_transitions_E1.java +++ b/src/main/java/simpaths/model/enums/Les_transitions_E1.java @@ -5,6 +5,8 @@ */ +import microsim.statistics.regression.IntegerValuedEnum; + public enum Les_transitions_E1 implements IntegerValuedEnum { NotEmployed(0), SelfEmployed(1), diff --git a/src/main/java/simpaths/model/enums/Les_transitions_FF1.java b/src/main/java/simpaths/model/enums/Les_transitions_FF1.java index f1e2a5835..a3175b4e9 100644 --- a/src/main/java/simpaths/model/enums/Les_transitions_FF1.java +++ b/src/main/java/simpaths/model/enums/Les_transitions_FF1.java @@ -5,6 +5,8 @@ */ +import microsim.statistics.regression.IntegerValuedEnum; + public enum Les_transitions_FF1 implements IntegerValuedEnum { NotEmployed(0), SelfEmployed(1), diff --git a/src/main/java/simpaths/model/enums/Les_transitions_FX1.java b/src/main/java/simpaths/model/enums/Les_transitions_FX1.java index c778b81ea..c713d30c8 100644 --- a/src/main/java/simpaths/model/enums/Les_transitions_FX1.java +++ b/src/main/java/simpaths/model/enums/Les_transitions_FX1.java @@ -5,6 +5,8 @@ */ +import microsim.statistics.regression.IntegerValuedEnum; + public enum Les_transitions_FX1 implements IntegerValuedEnum { NotEmployed(0), SelfEmployed(1), diff --git a/src/main/java/simpaths/model/enums/Les_transitions_S1.java b/src/main/java/simpaths/model/enums/Les_transitions_S1.java index c8b1e3826..dc8a460d3 100644 --- a/src/main/java/simpaths/model/enums/Les_transitions_S1.java +++ b/src/main/java/simpaths/model/enums/Les_transitions_S1.java @@ -5,6 +5,8 @@ */ +import microsim.statistics.regression.IntegerValuedEnum; + public enum Les_transitions_S1 implements IntegerValuedEnum { NotEmployed(0), Employee(1), diff --git a/src/main/java/simpaths/model/enums/Les_transitions_U1.java b/src/main/java/simpaths/model/enums/Les_transitions_U1.java index 42964b09c..71a780d5b 100644 --- a/src/main/java/simpaths/model/enums/Les_transitions_U1.java +++ b/src/main/java/simpaths/model/enums/Les_transitions_U1.java @@ -5,6 +5,8 @@ */ +import microsim.statistics.regression.IntegerValuedEnum; + public enum Les_transitions_U1 implements IntegerValuedEnum { NotEmployed(0), //Definition of this could be omitted - omitted category would act as the baseline in the multiprobit regression. But specified for clarity. Employee(1), diff --git a/src/main/java/simpaths/model/enums/MacroScenarioGreenPolicy.java b/src/main/java/simpaths/model/enums/MacroScenarioGreenPolicy.java new file mode 100644 index 000000000..1a1b9bcf1 --- /dev/null +++ b/src/main/java/simpaths/model/enums/MacroScenarioGreenPolicy.java @@ -0,0 +1,7 @@ +package simpaths.model.enums; + +public enum MacroScenarioGreenPolicy { + + Yes, + No +} diff --git a/src/main/java/simpaths/model/enums/MacroScenarioPopulation.java b/src/main/java/simpaths/model/enums/MacroScenarioPopulation.java new file mode 100644 index 000000000..d44045c9d --- /dev/null +++ b/src/main/java/simpaths/model/enums/MacroScenarioPopulation.java @@ -0,0 +1,9 @@ +package simpaths.model.enums; + +public enum MacroScenarioPopulation { + + Baseline, + High, + Low + +} diff --git a/src/main/java/simpaths/model/enums/MacroScenarioProductivity.java b/src/main/java/simpaths/model/enums/MacroScenarioProductivity.java new file mode 100644 index 000000000..f16fb9a09 --- /dev/null +++ b/src/main/java/simpaths/model/enums/MacroScenarioProductivity.java @@ -0,0 +1,9 @@ +package simpaths.model.enums; + +public enum MacroScenarioProductivity { + + Baseline, + High, + Low + +} diff --git a/src/main/java/simpaths/model/enums/NotPartnerInformalCarer.java b/src/main/java/simpaths/model/enums/NotPartnerInformalCarer.java index 9f8363bbe..a47694580 100644 --- a/src/main/java/simpaths/model/enums/NotPartnerInformalCarer.java +++ b/src/main/java/simpaths/model/enums/NotPartnerInformalCarer.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum NotPartnerInformalCarer implements IntegerValuedEnum { DaughterOnly(0), DaughterAndSon(1), diff --git a/src/main/java/simpaths/model/enums/OccupancyMacroShock.java b/src/main/java/simpaths/model/enums/OccupancyMacroShock.java new file mode 100644 index 000000000..72ea146b6 --- /dev/null +++ b/src/main/java/simpaths/model/enums/OccupancyMacroShock.java @@ -0,0 +1,14 @@ +package simpaths.model.enums; + +//For use with DonorHousehold class to filter into the appropriate occupancy types +public enum OccupancyMacroShock { + + Couple, + Single_Male, + Single_Female, + Male_With_Dependent, + Female_With_Dependent, + Male_AC, + Female_AC; + ; +} diff --git a/src/main/java/simpaths/model/enums/PartnerSupplementaryCarer.java b/src/main/java/simpaths/model/enums/PartnerSupplementaryCarer.java index 4e2ecb10a..c5a6235e7 100644 --- a/src/main/java/simpaths/model/enums/PartnerSupplementaryCarer.java +++ b/src/main/java/simpaths/model/enums/PartnerSupplementaryCarer.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum PartnerSupplementaryCarer implements IntegerValuedEnum { None(0), Daughter(1), diff --git a/src/main/java/simpaths/model/enums/Region.java b/src/main/java/simpaths/model/enums/Region.java index 3323309e4..0a455510c 100644 --- a/src/main/java/simpaths/model/enums/Region.java +++ b/src/main/java/simpaths/model/enums/Region.java @@ -1,15 +1,30 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum Region implements IntegerValuedEnum { //Uses NUTS Level 1 system for each country - + + // Poland + PL2("Poludniowy", 2), + PL4("Polnocno-Zachodni", 4), + PL5("Poludniowo-Zachodni", 5), + PL6("Polnocny", 6), + PL10("Centralno-Wschodni", 10), // "Centralno-Wschodni" = Central + East = Centralny (1->7) + Wschodni (3->8)+ Województwo Mazowieckie (9) + + + //Hungary //Name //EUROMOD drgn1 value + HUC("Central Hungary", 1), // HU1 + HUA("Transdanubia", 2), // HU2 + HUB("Great Plain and North", 3), // HU3 + //Italy //Name //EUROMOD drgn1 value - ITC("Nord Ovest", 1), //Nord Ovest 1 - ITF("Sud", 4), //Sud 4 - ITG("Isole", 5), //Isole 5 - ITH("Nord Est", 2), //Nord Est (formerly ITD) 2 - ITI("Centro", 3), //Centro (formerly ITE) 3 + ITC("Northwest", 3), //Nord Ovest 1 + ITF("South", 6), //Sud 4 + ITG("Islands", 7), //Isole 5 + ITH("Northeast", 8), //Nord Est (formerly ITD) 2 + ITI("Central", 9), //Centro (formerly ITE) 3 //See https://www.euromod.ac.uk/sites/default/files/country-reports/year6/Y7_CR_IT_Final.pdf page 41 for definition EUROMOD variable drgn2 which corresponds to NUTS level 2, from which can be imputed the NUTS level 1 and therefore meaning of drgn1 values. //UK //Name //EUROMOD drgn1 value diff --git a/src/main/java/simpaths/model/enums/ReversedIndicator.java b/src/main/java/simpaths/model/enums/ReversedIndicator.java new file mode 100644 index 000000000..96f194971 --- /dev/null +++ b/src/main/java/simpaths/model/enums/ReversedIndicator.java @@ -0,0 +1,17 @@ +package simpaths.model.enums; + +import microsim.statistics.regression.IntegerValuedEnum; + +/* + * The Indicator class is for use with regressions using dummy variables - boolean-like variables that take the value of either 0 or 1, depending on false or true respectively. + */ +public enum ReversedIndicator implements IntegerValuedEnum { + True(0), + False(1); + + private final int value; + ReversedIndicator(int val) { value = val; } + + @Override + public int getValue() {return value;} +} diff --git a/src/main/java/simpaths/model/enums/SocialCareProvision.java b/src/main/java/simpaths/model/enums/SocialCareProvision.java index 970c62f71..7e66e07f4 100644 --- a/src/main/java/simpaths/model/enums/SocialCareProvision.java +++ b/src/main/java/simpaths/model/enums/SocialCareProvision.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum SocialCareProvision implements IntegerValuedEnum { None(0), diff --git a/src/main/java/simpaths/model/enums/SocialCareReceipt.java b/src/main/java/simpaths/model/enums/SocialCareReceipt.java index 4e5df91db..e3ac3550c 100644 --- a/src/main/java/simpaths/model/enums/SocialCareReceipt.java +++ b/src/main/java/simpaths/model/enums/SocialCareReceipt.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + public enum SocialCareReceipt implements IntegerValuedEnum { None(0), Informal(1), diff --git a/src/main/java/simpaths/model/enums/SocialCareReceiptS2c.java b/src/main/java/simpaths/model/enums/SocialCareReceiptS2c.java index ba01dfb0d..c42fc2ef8 100644 --- a/src/main/java/simpaths/model/enums/SocialCareReceiptS2c.java +++ b/src/main/java/simpaths/model/enums/SocialCareReceiptS2c.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + // for interaction with multi-nomial logit (S2c) public enum SocialCareReceiptS2c implements IntegerValuedEnum { Informal(0), diff --git a/src/main/java/simpaths/model/enums/SocialCareReceiptState.java b/src/main/java/simpaths/model/enums/SocialCareReceiptState.java index 0f5edc221..95c7b95fe 100644 --- a/src/main/java/simpaths/model/enums/SocialCareReceiptState.java +++ b/src/main/java/simpaths/model/enums/SocialCareReceiptState.java @@ -1,5 +1,7 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; + // used to describe state for IO decisions // Relative to the population projections, IO decisions ignore two categories: // (1) those who do not need care are treated equivalently regardless of whether they receive care diff --git a/src/main/java/simpaths/model/enums/TargetShares.java b/src/main/java/simpaths/model/enums/TargetShares.java index f55c602ed..9cd664ff1 100644 --- a/src/main/java/simpaths/model/enums/TargetShares.java +++ b/src/main/java/simpaths/model/enums/TargetShares.java @@ -2,7 +2,11 @@ public enum TargetShares { Partnership, + Retirement, + Disability, + Students, EmploymentSingleMales, EmploymentSingleFemales, - EmploymentCouples; + EmploymentCouples, + Employment; } diff --git a/src/main/java/simpaths/model/enums/TimeSeriesVariable.java b/src/main/java/simpaths/model/enums/TimeSeriesVariable.java index 8fc4acca5..fc966e38f 100644 --- a/src/main/java/simpaths/model/enums/TimeSeriesVariable.java +++ b/src/main/java/simpaths/model/enums/TimeSeriesVariable.java @@ -3,7 +3,6 @@ public enum TimeSeriesVariable { CareProvisionAdjustment, CarerWageRate, - EmploymentAlignment, FixedRetirementAge, GDP, HighEducationRate, @@ -11,8 +10,12 @@ public enum TimeSeriesVariable { LowEducationRate, PartnershipAdjustment, FertilityAdjustment, + DisabilityAdjustment, + UtilityAdjustment, UtilityAdjustmentSingleMales, UtilityAdjustmentSingleFemales, UtilityAdjustmentCouples, + RetirementAdjustment, + InSchoolAdjustment, WageGrowth, } diff --git a/src/main/java/simpaths/model/enums/UnionMatchingMethod.java b/src/main/java/simpaths/model/enums/UnionMatchingMethod.java index 668385e99..c3fc1bc57 100644 --- a/src/main/java/simpaths/model/enums/UnionMatchingMethod.java +++ b/src/main/java/simpaths/model/enums/UnionMatchingMethod.java @@ -4,6 +4,5 @@ public enum UnionMatchingMethod { Parametric, //Use parametric matching based on wage and age differential ParametricNoRegion, //USe parametric matching as above first, and then relax region constraint and repeat matching - SBAM; //Use SBAM Matching method } diff --git a/src/main/java/simpaths/model/enums/Ydses_c5.java b/src/main/java/simpaths/model/enums/Ydses_c5.java index f6c63f745..394b434c5 100644 --- a/src/main/java/simpaths/model/enums/Ydses_c5.java +++ b/src/main/java/simpaths/model/enums/Ydses_c5.java @@ -1,9 +1,20 @@ package simpaths.model.enums; +import microsim.statistics.regression.IntegerValuedEnum; -public enum Ydses_c5 { - Q1, //This is the baseline (omitted) in the health status regression for example. - Q2, - Q3, - Q4, - Q5, +public enum Ydses_c5 implements IntegerValuedEnum { + Q1(1), //This is the baseline (omitted) in the health status regression for example. + Q2(2), + Q3(3), + Q4(4), + Q5(5), + ; + + private final int value; + + Ydses_c5(int val) {value = val;} + + @Override + public int getValue() { + return value; + } } diff --git a/src/main/java/simpaths/model/taxes/DonorPerson.java b/src/main/java/simpaths/model/taxes/DonorPerson.java index 2c3a4773c..b55020e5d 100644 --- a/src/main/java/simpaths/model/taxes/DonorPerson.java +++ b/src/main/java/simpaths/model/taxes/DonorPerson.java @@ -44,7 +44,7 @@ public long getId() { public Integer getAge() { return this.age; } public int getHoursWorkedWeekly() { return this.hoursWorkedWeekly; } public int getDlltsd() { return this.dlltsd; } - public int getCarer() { return this.carer; } + public int getCarer() { return 0; } public double getWeight() { return this.weight; } public Set getPolicies() { return policies; } public DonorPersonPolicy getPolicy(int startYear) { diff --git a/src/main/java/simpaths/model/taxes/DonorTaxImputation.java b/src/main/java/simpaths/model/taxes/DonorTaxImputation.java index 223dbe7f9..3231d3dd8 100644 --- a/src/main/java/simpaths/model/taxes/DonorTaxImputation.java +++ b/src/main/java/simpaths/model/taxes/DonorTaxImputation.java @@ -90,7 +90,7 @@ public void evaluate() { // use keys to extract candidate pool from database //------------------------------------------------------------ List candidatePool = null; - int matchRegime = -1; + int matchRegime = 0; int systemYear = getSystemYear(keys.getSimYear()); boolean flagSecondIncome = false, flagChildcareCost = false; for (int ii=0; ii 1.0E-4) { @@ -250,6 +251,7 @@ public void evaluate() { candidatesList = candidatesList.subList(0, candidateLast); + //------------------------------------------------------------ // impute disposable income from set of preferred candidates //------------------------------------------------------------ @@ -261,6 +263,9 @@ public void evaluate() { double infAdj = 1.0; if (systemYear != keys.getPriceYear()) infAdj = Parameters.getTimeSeriesIndex(keys.getPriceYear(), UpratingCase.TaxDonor) / Parameters.getTimeSeriesIndex(systemYear, UpratingCase.TaxDonor); + + boolean imputeDirectly = false; + for (CandidateList candidateList : candidatesList) { // loop over each preferred candidate @@ -273,10 +278,13 @@ public void evaluate() { if (keys.getRandomDraw()>0.0 || Math.abs(keys.getRandomDraw()+2.0)<1.0E-2) weight = 1.0; DonorTaxUnit candidate = candidateList.getCandidate(); - if ( keys.isLowIncome(matchRegime) ) { + // pre-calculate the disposable to gross income ratio + double ratio = candidate.getPolicyBySystemYear(systemYear).getDisposableIncomePerMonth() / candidate.getPolicyBySystemYear(systemYear).getOriginalIncomePerMonth(); + if ( keys.isLowIncome(matchRegime) || ratio >= 1.64 || ratio <= 0.58) { // impute based on observed disposable income disposableIncomePerWeek += candidate.getPolicyBySystemYear(systemYear).getDisposableIncomePerMonth() / Parameters.WEEKS_PER_MONTH * weight * infAdj; benefitsReceivedPerWeek += (candidate.getPolicyBySystemYear(systemYear).getBenMeansTestPerMonth() + candidate.getPolicyBySystemYear(systemYear).getBenNonMeansTestPerMonth()) / Parameters.WEEKS_PER_MONTH * weight * infAdj; + imputeDirectly = true; } else { // impute based on ratio of disposable to original income disposableIncomePerWeek += candidate.getPolicyBySystemYear(systemYear).getDisposableIncomePerMonth() / candidate.getPolicyBySystemYear(systemYear).getOriginalIncomePerMonth() * weight; @@ -290,7 +298,7 @@ public void evaluate() { } if (Math.abs(disposableIncomePerWeek+999.0)<1.0E-5) throw new RuntimeException("Failed to populate disposable income and benefits from donor with inner key value " + keys.getKey(0)); - if ( !keys.isLowIncome(matchRegime) ) { + if ( !keys.isLowIncome(matchRegime) && !imputeDirectly) { disposableIncomePerWeek *= keys.getOriginalIncomePerWeek(); benefitsReceivedPerWeek *= keys.getOriginalIncomePerWeek(); } diff --git a/src/main/java/simpaths/model/taxes/DonorTaxUnitPolicy.java b/src/main/java/simpaths/model/taxes/DonorTaxUnitPolicy.java index b0750c700..3b3301088 100644 --- a/src/main/java/simpaths/model/taxes/DonorTaxUnitPolicy.java +++ b/src/main/java/simpaths/model/taxes/DonorTaxUnitPolicy.java @@ -32,6 +32,7 @@ public class DonorTaxUnitPolicy { @Column(name = "DONOR_KEY2") private Integer donorKey2; @Column(name = "DONOR_KEY3") private Integer donorKey3; @Column(name = "DONOR_KEY4") private Integer donorKey4; + @Column(name = "DONOR_KEY5") private Integer donorKey5; /** @@ -140,6 +141,8 @@ public Integer getDonorKey(int regime) { return donorKey3; } else if (regime==4) { return donorKey4; + } else if (regime==5) { + return donorKey5; } else { throw new RuntimeException("request to get unrecognised donor key regime"); } @@ -155,6 +158,8 @@ public void setDonorKey(int regime, int key) { donorKey3 = key; } else if (regime==4) { donorKey4 = key; + } else if (regime==5) { + donorKey5 = key; } else { throw new RuntimeException("request to set unrecognised donor key regime"); } diff --git a/src/main/java/simpaths/model/taxes/IKeyFunction.java b/src/main/java/simpaths/model/taxes/IKeyFunction.java new file mode 100644 index 000000000..32ae3c06e --- /dev/null +++ b/src/main/java/simpaths/model/taxes/IKeyFunction.java @@ -0,0 +1,12 @@ +package simpaths.model.taxes; + +import java.util.Map; + +public interface IKeyFunction { + Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, + int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, int dlltsdWoman, + int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek); + int getMatchFeatureIndex(MatchFeature feature, int taxDBRegime, int keyValue); + boolean[] isLowIncome(Integer[] keys); + Map> getTaxdbCounter(); +} diff --git a/src/main/java/simpaths/model/taxes/KeyFunction.java b/src/main/java/simpaths/model/taxes/KeyFunction.java index 0f5ced0a5..628008901 100644 --- a/src/main/java/simpaths/model/taxes/KeyFunction.java +++ b/src/main/java/simpaths/model/taxes/KeyFunction.java @@ -20,21 +20,14 @@ public class KeyFunction { private double hoursWorkedPerWeekMan, hoursWorkedPerWeekWoman, originalIncomePerWeek, secondIncomePerWeek, childcareCostPerWeek; // define key function here - switchable - //private KeyFunction1 keyFunction; - //private KeyFunction2 keyFunction; - //private KeyFunction3 keyFunction; - private KeyFunction4 keyFunction; + private IKeyFunction keyFunction; /** * CONSTRUCTORS */ public KeyFunction() { - - // instantiate key function variant - //this.keyFunction = new KeyFunction1(); - //this.keyFunction = new KeyFunction2(); - this.keyFunction = new KeyFunction4(); + this.keyFunction = new KeyFunctionHU2(); } public KeyFunction(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, int dlltsdWoman, int careProvision, double originalIncomePerWeek) { @@ -92,7 +85,6 @@ public KeyFunction(int simYear, int priceYear, int age, int numberMembersOver17, this.secondIncomePerWeek = Math.max(0.0, Math.min(secondIncomePerWeek, originalIncomePerWeek - secondIncomePerWeek)); } - /** * GETTERS AND SETTERS */ @@ -196,14 +188,6 @@ public void setChildcareCostPerWeek(double childcareCostPerWeek) { this.childcareCostPerWeek = childcareCostPerWeek; } - public KeyFunction4 getKeyFunction() { - return keyFunction; - } - - public void setKeyFunction(KeyFunction4 keyFunction) { - this.keyFunction = keyFunction; - } - /** * WORKER METHODS */ @@ -222,10 +206,8 @@ public Integer[] evaluateKeys() { } public boolean[] isLowIncome(Integer[] keys) { - - if (keyFunction == null) { + if (keyFunction == null) throw new InvalidParameterException("call to evaluate donor keys before KeyFunction populated"); - } return keyFunction.isLowIncome(keys); } diff --git a/src/main/java/simpaths/model/taxes/KeyFunction0.java b/src/main/java/simpaths/model/taxes/KeyFunction0.java new file mode 100644 index 000000000..1c169e389 --- /dev/null +++ b/src/main/java/simpaths/model/taxes/KeyFunction0.java @@ -0,0 +1,304 @@ +package simpaths.model.taxes; + +import simpaths.data.Parameters; +import simpaths.model.decisions.DecisionParams; +import simpaths.model.enums.UpratingCase; + +import java.util.HashMap; +import java.util.Map; + + +/** + * + * CLASS TO MANAGE ONE SPECIFICATION FOR EVALUATING DONOR KEYS USED TO IMPUTE TAX AND BENEFIT PAYMENTS + * + */ +public class KeyFunction0 implements IKeyFunction { + + + /** + * ATTRIBUTES + */ + private final int MID_AGE = 45; + private final int INCOME_REF_YEAR = 2017; + private final double LO_INCOME = 225.0; + private final double HI_INCOME = 710.0; + + + /** + * CONSTRUCTORS + */ + public KeyFunction0() {} + + /** + * METHOD TO EVALUATE DONOR KEYS FOR COARSE EXACT MATCHING + */ + public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, + int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, + int dlltsdWoman, int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { + + // initialise working variables + int spa = getStatePensionAge(age, simYear); + Map> taxdbCounter = getTaxdbCounter(); + Map> units = new HashMap<>(); + Integer[] result = new Integer[Parameters.TAXDB_REGIMES]; + Map localMap; + + // discretise hours worked variables + int partTimeEmployed = 0, fullTimeEmployed = 0; + if (hoursWorkedPerWeekMan >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekMan > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + if (hoursWorkedPerWeekWoman >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekWoman > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + + //------------------------------------------------------ + // evaluate characteristic-specific steps + //------------------------------------------------------ + + // age + localMap = new HashMap<>(); + if (age >= spa) { + localMap.put(0,2); + localMap.put(1,1); + localMap.put(2,1); + } else if (age >= MID_AGE) { + localMap.put(0,1); + localMap.put(1,0); + localMap.put(2,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + } + units.put(MatchFeature.Age, localMap); + + // adults + localMap = new HashMap<>(); + if (numberMembersOver17 > 1) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + } + units.put(MatchFeature.Adults, localMap); + + // children + localMap = new HashMap<>(); + if ( age < spa ) { + + localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(1, Math.min(numberChildrenUnder5,1) + 2 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(2, Math.min(numberChildrenUnder5 + numberChildren5To9+numberChildren10To17,3)); + } else { + + localMap.put(0, 0); + localMap.put(1, 0); + localMap.put(2, 0); + } + units.put(MatchFeature.Children, localMap); + + // employment + localMap = new HashMap<>(); + if (partTimeEmployed + fullTimeEmployed == 0) { + // no employment + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + } else if ( fullTimeEmployed == 0 ){ + // only part-time employed + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,0); + } else if ( partTimeEmployed + fullTimeEmployed == 1 ){ + // one full-time employed + localMap.put(0,2); + localMap.put(1,1); + localMap.put(2,0); + } else if ( partTimeEmployed == 1 & fullTimeEmployed == 1 ){ + // one full-time and one part-time employed + localMap.put(0,3); + localMap.put(1,2); + localMap.put(2,0); + } else { + // two full-time employed + localMap.put(0,4); + localMap.put(1,2); + localMap.put(2,0); + } + units.put(MatchFeature.Employment, localMap); + + // original income + localMap = new HashMap<>(); + double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / + Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); + if (originalIncomePerWeekAdjusted < LO_INCOME) { + // low income + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + } else if ( originalIncomePerWeekAdjusted < HI_INCOME ) { + // mid income + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + } else { + // high income + localMap.put(0,2); + localMap.put(1,1); + localMap.put(2,1); + } + units.put(MatchFeature.Income, localMap); + + //------------------------------------------------------ + // compile results + //------------------------------------------------------ + for (int ii=0; ii> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + + /** + * WORKER METHOD TO PROVIDE STATE PENSION AGE AND YEAR + * @param age age of eldest family member + * @param simYear simulated year + * @return state pension age + */ + private int getStatePensionAge(int age, int simYear) { + + int spa; + if (simYear - age + 65 < 2019) { + spa = 65; + } else if (simYear - age + 66 < 2027) { + spa = 66; + } else if (simYear - age + 67 < 2045) { + spa = 67; + } else { + spa = 68; + } + return spa; + } + + /** + * WORKER METHOD TO CALL OR INITIALISE THE COUNTER MAPPING FOR DONOR KEYS + * @return taxdbCounter populated as implied by current matching function + */ + public Map> getTaxdbCounter() { + + Map> taxdbCounter = Parameters.getTaxdbCounter(); + if (taxdbCounter.isEmpty()) { + + // initialise working variables + Map mapLocal; + int[] ptsLocal; + + // initialise starting values + ptsLocal = new int[]{1,1,1}; + mapLocal = new HashMap<>(); + for ( int ii=0; ii<3; ii++) { + mapLocal.put(ii,1); + } + + // age + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Age,mapLocal); + ptsLocal = new int[]{3,2,2}; // this defines the number of age alternatives considered for each donor key set + + // number of adults + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Adults,mapLocal); + ptsLocal = new int[]{2,2,2}; + + // number of children + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Children,mapLocal); + ptsLocal = new int[]{3*4,2*4,4}; + + // employment status + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Employment,mapLocal); + ptsLocal = new int[]{5,3,1}; + + // original income + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Income,mapLocal); + ptsLocal = new int[]{3,2,2}; + + // total size + mapLocal = updateMap(mapLocal, ptsLocal); + taxdbCounter.put(MatchFeature.Final,mapLocal); + + Parameters.setTaxdbCounter(taxdbCounter); + } + + return taxdbCounter; + } + + /** + * WORKER METHOD TO INCREMENT THE STEP EVALUATION FOR taxdbCounter + * @param mapPrev the immediately preceding step + * @param ptsPrev the immediately preceding points to increment step to current state + * @return the updated step evaluation + */ + private Map updateMap(Map mapPrev, int[] ptsPrev) { + + Map mapHere = new HashMap<>(); + for ( int ii=0; ii evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To17, - double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, double originalIncomePerWeek) { + public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, + int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, + int dlltsdWoman, int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { // initialise working variables int spa = getStatePensionAge(age, simYear); Map> taxdbCounter = getTaxdbCounter(); Map> units = new HashMap<>(); - List result = new ArrayList<>(); + Integer[] result = new Integer[Parameters.TAXDB_REGIMES]; Map localMap; // discretise hours worked variables @@ -106,9 +97,9 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe localMap = new HashMap<>(); if ( age < spa ) { - localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To17,3)); - localMap.put(1, Math.min(numberChildrenUnder5,1) + 2 * Math.min(numberChildren5To17,3)); - localMap.put(2, Math.min(numberChildrenUnder5 + numberChildren5To17,3)); + localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(1, Math.min(numberChildrenUnder5,1) + 2 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(2, Math.min(numberChildrenUnder5 + numberChildren5To9+numberChildren10To17,3)); } else { localMap.put(0, 0); @@ -178,7 +169,7 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe if (units.containsKey(feature)) index += units.get(feature).get(ii) * taxdbCounter.get(feature).get(ii); } - result.add(index); + result[ii] = index; } // return @@ -187,21 +178,40 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe /** * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING - * @param priceYear year of prices used to measure income - * @param originalIncomePerWeek original income per week of family - * @return boolean equal to true if family treated as low income */ - public boolean isLowIncome(int priceYear, double originalIncomePerWeek) { + public boolean[] isLowIncome(Integer[] keys) { - boolean lowIncome = false; - double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / - Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); - if (originalIncomePerWeekAdjusted < LO_INCOME) { - lowIncome = true; + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; + for (int regime=0; regime> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + /** * WORKER METHOD TO PROVIDE STATE PENSION AGE AND YEAR * @param age age of eldest family member diff --git a/src/main/java/simpaths/model/taxes/KeyFunction2.java b/src/main/java/simpaths/model/taxes/KeyFunction2.java index 8dbf7d2fc..b91c7f500 100644 --- a/src/main/java/simpaths/model/taxes/KeyFunction2.java +++ b/src/main/java/simpaths/model/taxes/KeyFunction2.java @@ -15,7 +15,7 @@ * CLASS TO MANAGE ONE SPECIFICATION FOR EVALUATING DONOR KEYS USED TO IMPUTE TAX AND BENEFIT PAYMENTS * */ -public class KeyFunction2 { +public class KeyFunction2 implements IKeyFunction { /** @@ -34,27 +34,16 @@ public KeyFunction2() {} /** * METHOD TO EVALUATE DONOR KEYS FOR COARSE EXACT MATCHING - * @param simYear simulated year - * @param priceYear year of prices used to measure financial statistics - * @param age simulated age - * @param numberMembersOver17 family members aged 18+ - * @param numberChildrenUnder5 family members under age 5 - * @param numberChildren5To17 family members aged 5 to 17 - * @param hoursWorkedPerWeekMan employment hours per week of adult male - * @param hoursWorkedPerWeekWoman employment hours per week of adult female - * @param dlltsdMan disability status of man - * @param dlltsdWoman disability status of woman - * @param originalIncomePerWeek original income per week of family (possibly negative) - * @return Integer list of keys, ordered from most fine (0) to most coarse (2) */ - public List evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To17, - double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, int dlltsdWoman, double originalIncomePerWeek) { + public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, + int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, + int dlltsdWoman, int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { // initialise working variables int spa = getStatePensionAge(age, simYear); Map> taxdbCounter = getTaxdbCounter(); Map> units = new HashMap<>(); - List result = new ArrayList<>(); + Integer[] result = new Integer[Parameters.TAXDB_REGIMES]; Map localMap; // discretise hours worked variables @@ -108,9 +97,9 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe localMap = new HashMap<>(); if ( age < spa ) { - localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To17,3)); - localMap.put(1, Math.min(numberChildrenUnder5,1) + 2 * Math.min(numberChildren5To17,3)); - localMap.put(2, Math.min(numberChildrenUnder5 + numberChildren5To17,3)); + localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(1, Math.min(numberChildrenUnder5,1) + 2 * Math.min(numberChildren5To9+numberChildren10To17,3)); + localMap.put(2, Math.min(numberChildrenUnder5 + numberChildren5To9+numberChildren10To17,3)); } else { localMap.put(0, 0); @@ -195,7 +184,7 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe if (units.containsKey(feature)) index += units.get(feature).get(ii) * taxdbCounter.get(feature).get(ii); } - result.add(index); + result[ii] = index; } // return @@ -204,21 +193,40 @@ public List evaluateKeys(int simYear, int priceYear, int age, int numbe /** * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING - * @param priceYear year of prices used to measure income - * @param originalIncomePerWeek original income per week of family - * @return boolean equal to true if family treated as low income */ - public boolean isLowIncome(int priceYear, double originalIncomePerWeek) { + public boolean[] isLowIncome(Integer[] keys) { - boolean lowIncome = false; - double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / - Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); - if (originalIncomePerWeekAdjusted < LO_INCOME) { - lowIncome = true; + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; + for (int regime=0; regime> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + /** * WORKER METHOD TO PROVIDE STATE PENSION AGE AND YEAR * @param age age of eldest family member diff --git a/src/main/java/simpaths/model/taxes/KeyFunction3.java b/src/main/java/simpaths/model/taxes/KeyFunction3.java index 847c28ec1..8d00fe3c1 100644 --- a/src/main/java/simpaths/model/taxes/KeyFunction3.java +++ b/src/main/java/simpaths/model/taxes/KeyFunction3.java @@ -12,7 +12,7 @@ * CLASS TO MANAGE ONE SPECIFICATION FOR EVALUATING DONOR KEYS USED TO IMPUTE TAX AND BENEFIT PAYMENTS * */ -public class KeyFunction3 { +public class KeyFunction3 implements IKeyFunction { /** @@ -47,7 +47,7 @@ public KeyFunction3() {} */ public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, int dlltsdWoman, - double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { + int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { // initialise working variables int spa = getStatePensionAge(age, simYear); @@ -267,19 +267,39 @@ public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMem return result; } + public int getMatchFeatureIndex(MatchFeature feature, int taxDBRegime, int keyValue) { + + Map> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + + /** * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING - * @param priceYear year of prices used to measure income - * @param originalIncomePerWeek original income per week of family - * @return boolean equal to true if family treated as low income */ - public boolean isLowIncome(int priceYear, double originalIncomePerWeek) { + public boolean[] isLowIncome(Integer[] keys) { - boolean lowIncome = false; - double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / - Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); - if (originalIncomePerWeekAdjusted < LO_INCOME) { - lowIncome = true; + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; + for (int regime=0; regime> taxdbCounter = getTaxdbCounter(); int keyLocal = keyValue; for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + MatchFeature featureHere = MatchFeature.values()[ii]; try { int size = taxdbCounter.get(featureHere).get(taxDBRegime); @@ -327,13 +328,12 @@ public int getMatchFeatureIndex(MatchFeature feature, int taxDBRegime, int keyVa * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING */ public boolean[] isLowIncome(Integer[] keys) { + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; - for (int regime=0;regime1 && index==0) ) - lowIncome[regime] = true; - else - lowIncome[regime] = false; + lowIncome[regime] = (regime <= 1 && index == 1) || (regime > 1 && index == 0); } return lowIncome; } diff --git a/src/main/java/simpaths/model/taxes/KeyFunctionHU.java b/src/main/java/simpaths/model/taxes/KeyFunctionHU.java new file mode 100644 index 000000000..5e2f2bfa3 --- /dev/null +++ b/src/main/java/simpaths/model/taxes/KeyFunctionHU.java @@ -0,0 +1,433 @@ +package simpaths.model.taxes; + +import simpaths.data.Parameters; +import simpaths.model.decisions.DecisionParams; +import simpaths.model.enums.UpratingCase; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + + +/** + * + * CLASS TO MANAGE ONE SPECIFICATION FOR EVALUATING DONOR KEYS USED TO IMPUTE TAX AND BENEFIT PAYMENTS + * + */ +public class KeyFunctionHU implements IKeyFunction { + + + /** + * ATTRIBUTES + */ + private final int MID_AGE = 45; + private final int INCOME_REF_YEAR = 2018; + private final double LO_INCOME = 191.0; + private final double HI_INCOME = 573.0; + + + /** + * CONSTRUCTORS + */ + public KeyFunctionHU() {} + + + /** + * METHOD TO EVALUATE DONOR KEYS FOR COARSE EXACT MATCHING + * @param simYear simulated year + * @param priceYear year of prices used to measure financial statistics + * @param age simulated age + * @param numberMembersOver17 family members aged 18+ + * @param numberChildrenUnder5 family members under age 5 + * @param numberChildren5To9 family members aged 5 to 9 + * @param numberChildren10To17 family members aged 10 to 17 + * @param hoursWorkedPerWeekMan employment hours per week of adult male + * @param hoursWorkedPerWeekWoman employment hours per week of adult female + * @param dlltsdMan disability status of man + * @param dlltsdWoman disability status of woman + * @param careProvision indicator that at least one member of household provides social care + * @param originalIncomePerWeek original income per week of family (possibly negative) + * @return Integer list of keys, ordered from most fine (0) to most coarse (2) + */ + public Integer[] evaluateKeys(int simYear, int priceYear, int age, int numberMembersOver17, int numberChildrenUnder5, int numberChildren5To9, + int numberChildren10To17, double hoursWorkedPerWeekMan, double hoursWorkedPerWeekWoman, int dlltsdMan, int dlltsdWoman, + int careProvision, double originalIncomePerWeek, double secondIncomePerWeek, double childcareCostPerWeek) { + + // initialise working variables + int spa = Parameters.getStatePensionAge(simYear, age); + Map> taxdbCounter = getTaxdbCounter(); + Map> units = new HashMap<>(); + Integer[] result = new Integer[Parameters.TAXDB_REGIMES]; + Map localMap; + + // discretise hours worked variables + int partTimeEmployed = 0, fullTimeEmployed = 0; + if (hoursWorkedPerWeekMan >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekMan > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + if (hoursWorkedPerWeekWoman >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekWoman > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + + //------------------------------------------------------ + // evaluate characteristic-specific steps + //------------------------------------------------------ + + // age + localMap = new HashMap<>(); + if (age >= spa) { + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,0); + } else if (age >= MID_AGE) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,0); + localMap.put(4,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.Age, localMap); + + // adults + localMap = new HashMap<>(); + if (numberMembersOver17 > 1) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.Adults, localMap); + + // children + localMap = new HashMap<>(); + if ( age < spa ) { + localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(1, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(2, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(3, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9 + numberChildren10To17,2)); + localMap.put(4, Math.min(numberChildrenUnder5 + numberChildren5To9 + numberChildren10To17,3)); + } else { + localMap.put(0, 0); + localMap.put(1, 0); + localMap.put(2, 0); + localMap.put(3, 0); + localMap.put(4, 0); + } + units.put(MatchFeature.Children, localMap); + + // employment + localMap = new HashMap<>(); + if (partTimeEmployed + fullTimeEmployed == 0) { + // no employment + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else if ( fullTimeEmployed == 0 ){ + // only part-time employed + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,0); + } else if ( partTimeEmployed + fullTimeEmployed == 1 ){ + // one full-time employed + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,0); + } else if ( partTimeEmployed == 1 & fullTimeEmployed == 1 ){ + // one full-time and one part-time employed + localMap.put(0,3); + localMap.put(1,3); + localMap.put(2,3); + localMap.put(3,2); + localMap.put(4,0); + } else { + // two full-time employed + localMap.put(0,4); + localMap.put(1,4); + localMap.put(2,4); + localMap.put(3,2); + localMap.put(4,0); + } + units.put(MatchFeature.Employment, localMap); + + // long-term sick and disabled + localMap = new HashMap<>(); + if ((dlltsdMan > 0 || dlltsdWoman > 0) && !Parameters.flagSuppressSocialCareCosts) { + // one adult disabled and one able-bodied + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else { + // no disabled + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.Disability, localMap); + + // social care provision + localMap = new HashMap<>(); + if (careProvision > 0 && !Parameters.flagSuppressSocialCareCosts) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,0); + localMap.put(4,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.CareProvision, localMap); + + // original income + localMap = new HashMap<>(); + double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / + Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); + if (originalIncomePerWeekAdjusted < -LO_INCOME) { + // substantial negative income + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else if (originalIncomePerWeekAdjusted < LO_INCOME) { + // low income + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else if ( originalIncomePerWeekAdjusted < HI_INCOME ) { + // mid income + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,0); + } else { + // high income + localMap.put(0,3); + localMap.put(1,3); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,0); + } + units.put(MatchFeature.Income, localMap); + + // second income + localMap = new HashMap<>(); + if (secondIncomePerWeek > 0.01) { + localMap.put(0,1); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.DualIncome, localMap); + + // childcare costs + localMap = new HashMap<>(); + if (childcareCostPerWeek > 0.01) { + localMap.put(0,1); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + } + units.put(MatchFeature.Childcare, localMap); + + //------------------------------------------------------ + // compile results + //------------------------------------------------------ + for (int ii=0; ii> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + + + /** + * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING + */ + public boolean[] isLowIncome(Integer[] keys) { + + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; + for (int regime=0; regime 1 && index == 0); + } + return lowIncome; + } + + + /** + * WORKER METHOD TO CALL OR INITIALISE THE COUNTER MAPPING FOR DONOR KEYS + * @return taxdbCounter populated as implied by current matching function + */ + public Map> getTaxdbCounter() { + + Map> taxdbCounter = Parameters.getTaxdbCounter(); + if (taxdbCounter.isEmpty()) { + + // initialise working variables + Map mapLocal; + int[] ptsLocal; + + // initialise starting values + ptsLocal = new int[Parameters.TAXDB_REGIMES]; + Arrays.fill(ptsLocal, 1); + mapLocal = new HashMap<>(); + for ( int ii=0; ii updateMap(Map mapPrev, int[] ptsPrev) { + + Map mapHere = new HashMap<>(); + for ( int ii=0; ii> taxdbCounter = getTaxdbCounter(); + Map> units = new HashMap<>(); + Integer[] result = new Integer[Parameters.TAXDB_REGIMES]; + Map localMap; + + // discretise hours worked variables + int partTimeEmployed = 0, fullTimeEmployed = 0; + if (hoursWorkedPerWeekMan >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekMan > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + if (hoursWorkedPerWeekWoman >= DecisionParams.PARTTIME_HOURS_WEEKLY) { + fullTimeEmployed += 1; + } else if (hoursWorkedPerWeekWoman > DecisionParams.MIN_WORK_HOURS_WEEKLY) { + partTimeEmployed += 1; + } + + //------------------------------------------------------ + // evaluate characteristic-specific steps + //------------------------------------------------------ + + // age + localMap = new HashMap<>(); + if (age >= spa) { + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,1); + localMap.put(5,0); + } else if (age >= MID_AGE) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.Age, localMap); + + // adults + localMap = new HashMap<>(); + if (numberMembersOver17 > 1) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,1); + localMap.put(5,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.Adults, localMap); + + // children + localMap = new HashMap<>(); + if ( age < spa ) { + localMap.put(0, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(1, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(2, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9,2) + 9 * Math.min(numberChildren10To17,1)); + localMap.put(3, Math.min(numberChildrenUnder5,2) + 3 * Math.min(numberChildren5To9 + numberChildren10To17,2)); + localMap.put(4, Math.min(numberChildrenUnder5 + numberChildren5To9 + numberChildren10To17,3)); + localMap.put(5, Math.min(numberChildrenUnder5 + numberChildren5To9 + numberChildren10To17,3)); + } else { + localMap.put(0, 0); + localMap.put(1, 0); + localMap.put(2, 0); + localMap.put(3, 0); + localMap.put(4, 0); + localMap.put(5,0); + } + units.put(MatchFeature.Children, localMap); + + // employment + localMap = new HashMap<>(); + if (partTimeEmployed + fullTimeEmployed == 0) { + // no employment + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else if ( fullTimeEmployed == 0 ){ + // only part-time employed + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,0); + localMap.put(5,0); + } else if ( partTimeEmployed + fullTimeEmployed == 1 ){ + // one full-time employed + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,0); + localMap.put(5,0); + } else if ( partTimeEmployed == 1 & fullTimeEmployed == 1 ){ + // one full-time and one part-time employed + localMap.put(0,3); + localMap.put(1,3); + localMap.put(2,3); + localMap.put(3,2); + localMap.put(4,0); + localMap.put(5,0); + } else { + // two full-time employed + localMap.put(0,4); + localMap.put(1,4); + localMap.put(2,4); + localMap.put(3,2); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.Employment, localMap); + + // long-term sick and disabled + localMap = new HashMap<>(); + if ((dlltsdMan > 0 || dlltsdWoman > 0) && !Parameters.flagSuppressSocialCareCosts) { + // one adult disabled and one able-bodied + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else { + // no disabled + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.Disability, localMap); + + // social care provision + localMap = new HashMap<>(); + if (careProvision > 0 && !Parameters.flagSuppressSocialCareCosts) { + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,1); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.CareProvision, localMap); + + // original income + localMap = new HashMap<>(); + double originalIncomePerWeekAdjusted = originalIncomePerWeek * Parameters.getTimeSeriesIndex(INCOME_REF_YEAR, UpratingCase.TaxDonor) / + Parameters.getTimeSeriesIndex(priceYear, UpratingCase.TaxDonor); + if (originalIncomePerWeekAdjusted < -LO_INCOME) { + // substantial negative income + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else if (originalIncomePerWeekAdjusted < LO_INCOME) { + // low income + localMap.put(0,1); + localMap.put(1,1); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else if ( originalIncomePerWeekAdjusted < HI_INCOME ) { + // mid income + localMap.put(0,2); + localMap.put(1,2); + localMap.put(2,1); + localMap.put(3,1); + localMap.put(4,1); + localMap.put(5,0); + } else { + // high income + localMap.put(0,3); + localMap.put(1,3); + localMap.put(2,2); + localMap.put(3,1); + localMap.put(4,1); + localMap.put(5,0); + } + units.put(MatchFeature.Income, localMap); + + // second income + localMap = new HashMap<>(); + if (secondIncomePerWeek > 0.01) { + localMap.put(0,1); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.DualIncome, localMap); + + // childcare costs + localMap = new HashMap<>(); + if (childcareCostPerWeek > 0.01) { + localMap.put(0,1); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } else { + localMap.put(0,0); + localMap.put(1,0); + localMap.put(2,0); + localMap.put(3,0); + localMap.put(4,0); + localMap.put(5,0); + } + units.put(MatchFeature.Childcare, localMap); + + //------------------------------------------------------ + // compile results + //------------------------------------------------------ + for (int ii=0; ii> taxdbCounter = getTaxdbCounter(); + int keyLocal = keyValue; + for (int ii = MatchFeature.values().length-1; ii>=0; ii--) { + + MatchFeature featureHere = MatchFeature.values()[ii]; + try { + int size = taxdbCounter.get(featureHere).get(taxDBRegime); + int index = keyLocal / size; + if (feature.equals(featureHere)) + return index; + else + keyLocal -= index * size; + } catch (Exception e) { + System.out.println("Issue retrieving feature" + featureHere + "for regime " + taxDBRegime); + e.printStackTrace(); + } + } + throw new RuntimeException("failed to identify match feature for indexing"); + } + + + /** + * METHOD TO INDICATE IF TAX UNIT IS MEMBER OF 'LOW INCOME' CATEGORY FOR DATABASE MATCHING + */ + public boolean[] isLowIncome(Integer[] keys) { + + boolean[] lowIncome = new boolean[Parameters.TAXDB_REGIMES]; + for (int regime=0; regime 1 && index == 0); + } + return lowIncome; + } + + + /** + * WORKER METHOD TO CALL OR INITIALISE THE COUNTER MAPPING FOR DONOR KEYS + * @return taxdbCounter populated as implied by current matching function + */ + public Map> getTaxdbCounter() { + + Map> taxdbCounter = Parameters.getTaxdbCounter(); + if (taxdbCounter.isEmpty()) { + + // initialise working variables + Map mapLocal; + int[] ptsLocal; + + // initialise starting values + ptsLocal = new int[Parameters.TAXDB_REGIMES]; + Arrays.fill(ptsLocal, 1); + mapLocal = new HashMap<>(); + for ( int ii=0; ii updateMap(Map mapPrev, int[] ptsPrev) { + + Map mapHere = new HashMap<>(); + for ( int ii=0; ii