private bool IsOutputElig(HH hh, List <Person> tu) { if (parWho == null) { return(true); } return(FunInSpineBase.IsCondMetByTU(hh, tu, indexEligVar, parWho.GetCateg())); }
private void RunParallel(SpineAdmin spineManager) { string frac = reportingFraction == 100 ? "%" : "/" + reportingFraction; foreach (FunOutOfSpineBase fun in spineManager.runBeforeSpine) { fun.Run(); // run pre-spine functions (e.g. Keep/DropUnit, etc.) } int totalHHs = infoStore.hhAdmin.hhs.Count; int currentHH = 0; int currentPerc = 0; Parallel.ForEach <HH>(infoStore.hhAdmin.hhs, hh => // for each household run spine-functions (BenCalc, Elig, etc.) { int curFunIndex = 0; while (true) { FunInSpineBase fun = spineManager.GetNextFun(ref curFunIndex, hh) as FunInSpineBase; if (fun == null) { break; } foreach (List <Person> tu in hh.GetTUs(fun.GetTUName())) // loop over TUs within household { fun.Run(hh, tu); } } Interlocked.Increment(ref currentHH); if (reportingFraction * currentHH / totalHHs > currentPerc) // use int division here! { currentPerc = reportingFraction * currentHH / totalHHs; if (!infoStore.communicator.ReportProgress(new Communicator.ProgressInfo() { id = "Running spine", message = $"Running spine.. {currentPerc}{frac}" })) { throw new OperationCanceledException(); // note: one cannot simply break a Parallel.ForEach } } }); foreach (FunOutOfSpineBase fun in spineManager.runAfterSpine) { fun.Run(); // run post-spine functions (DefOutput, etc.) } }
private void InitVar(HH hh, out int nElig) { nElig = 0; foreach (List <Person> tu in hh.GetTUs(eligUnit)) { bool isMet = parEligUnitCond == null ? true : FunInSpineBase.IsCondMetByTU(hh, tu, parEligUnitCond, who); if (isMet) { ++nElig; } hh.SetTUValue(isMet ? 1 : 0, varIndexIsElig, tu); // on TU-level: set isULElig_loopname hh.SetTUValue(isMet ? nElig : 0, varIndexIsEligInIter, tu); // on TU-level: set isEligInIter_loopname } for (int p = 0; p < hh.GetPersonCount(); ++p) { hh.SetPersonValue(nElig, varIndexNElig, p); // on HH-level: set nULElig_loopname } }
private bool RunSequential(SpineAdmin spineManager) { int curFunIndex = 0; Dictionary <FunBase, List <FunUnitLoop> > unitLoopRanges = spineManager.GetUnitLoopRangesForSequentialRun(); while (true) // loop over functions { FunBase fun = spineManager.GetNextFun(ref curFunIndex); if (fun == null) { break; } DefFun.RUN_MODE runMode = // find out if the function expects to be run within HH-loop or not DefinitionAdmin.GetFunDefinition(fun.description.GetFunName()).runMode; if (runMode != DefFun.RUN_MODE.IN_SPINE) { (fun as FunOutOfSpineBase).Run(); // concerns functions usually running pre- or post-spine (DefOutput, Totals, etc.) } else { // concerns functions usually running in spine (BenCalc, Elig, etc.) FunInSpineBase spineFun = fun as FunInSpineBase; if (infoStore.runConfig.forceSequentialRun) { // run in a single thread foreach (HH hh in infoStore.hhAdmin.hhs) { foreach (List <Person> tu in hh.GetTUs(spineFun.GetTUName())) { SpineFunRun(spineFun, hh, tu); } } } else { // run in multiple threads Parallel.ForEach <HH>(infoStore.hhAdmin.hhs, hh => { foreach (List <Person> tu in hh.GetTUs(spineFun.GetTUName())) { SpineFunRun(spineFun, hh, tu); } }); } } if (!infoStore.communicator.ReportProgress( new Communicator.ProgressInfo() { message = $"Done with function {fun.description.Get(true)}" })) { return(false); } } return(true); void SpineFunRun(FunInSpineBase spineFun, HH hh, List <Person> tu) { bool run = false; if (unitLoopRanges.ContainsKey(spineFun)) // there are UnitLoops in the spine { // note that a function may be enclosed by more than one UnitLoop (see NRR add-on) foreach (FunUnitLoop ul in unitLoopRanges[spineFun]) // if any of the UnitLoops allows running - run { if (!ul.IsFinished(hh)) { run = true; } } } else { run = true; // the usual case - no UnitLoops } if (run) { spineFun.Run(hh, tu); } } }
protected override void DoFunWork() { // prepare the results dictionary - note that some cases overlap and should only be calculated once Dictionary <string, double> results = new Dictionary <string, double>(); Dictionary <string, List <List <double> > > valueList = new Dictionary <string, List <List <double> > >(); double countObservations = 0; foreach (ParVarIL agg in aggs) { foreach (string key in actions) { switch (key) { case DefPar.Totals.Varname_Sum: case DefPar.Totals.Varname_Mean: case DefPar.Totals.Varname_Count: case DefPar.Totals.Varname_PosCount: case DefPar.Totals.Varname_NegCount: case DefPar.Totals.Varname_Median: results.Add(key + agg.GetName(), 0.0); break; case DefPar.Totals.Varname_Decile: for (int i = 1; i < 10; i++) { results.Add(key + i + agg.GetName(), 0.0); } break; case DefPar.Totals.Varname_Quintile: for (int i = 1; i < 5; i++) { results.Add(key + i + agg.GetName(), 0.0); } break; case DefPar.Totals.Varname_Min: results.Add(key + agg.GetName(), double.MaxValue); break; case DefPar.Totals.Varname_Max: results.Add(key + agg.GetName(), double.MinValue); break; } } // mean also needs SUM, so add it if it does not already exist if (hasMean && !hasSum) { results.Add(DefPar.Totals.Varname_Sum + agg.GetName(), 0.0); } if (hasMedian || hasQuint || hasDec) { valueList.Add(agg.GetName(), new List <List <double> >()); } } // then go through each household and do the calculations foreach (HH hh in infoStore.hhAdmin.hhs) { foreach (List <Person> tu in hh.GetTUs(coParTU.name)) { if (include == null || FunInSpineBase.IsCondMetByTU(hh, tu, include.Item1, include.Item2)) { double weight = (useWeights ? hh.GetPersonValue(indexDwt, tu[0].indexInHH) : 1); countObservations += weight; foreach (ParVarIL agg in aggs) { double tuValue = agg.GetValue(hh, tu); double tuValueWeighted = tuValue * weight; foreach (string key in actions) { string res = key + agg.GetName(); switch (key) { case DefPar.Totals.Varname_Count: if (tuValue != 0) { results[res] += weight; } break; case DefPar.Totals.Varname_PosCount: if (tuValue > 0) { results[res] += weight; } break; case DefPar.Totals.Varname_NegCount: if (tuValue < 0) { results[res] += weight; } break; case DefPar.Totals.Varname_Min: if (tuValue < results[res]) { results[res] = tuValue; } break; case DefPar.Totals.Varname_Max: if (tuValue > results[res]) { results[res] = tuValue; } break; } } if (hasSum || hasMean) { results[DefPar.Totals.Varname_Sum + agg.GetName()] += tuValueWeighted; } if (hasMedian || hasQuint || hasDec) { valueList[agg.GetName()].Add(new List <double>() { tuValue, weight }); } } } } } // do any final calculations required and get the final results foreach (ParVarIL agg in aggs) { // calculate the mean if (hasMean) { results[DefPar.Totals.Varname_Mean + agg.GetName()] = results[DefPar.Totals.Varname_Sum + agg.GetName()] / countObservations; } // calculate the median and deciles if (hasMedian || hasQuint || hasDec) { bool findMedian = hasMedian, findQuint = hasQuint, findDec = hasDec; valueList[agg.GetName()] = valueList[agg.GetName()].OrderBy(p => p[0]).ToList(); double allObs = valueList[agg.GetName()].Sum(p => p[1]); double halfObs = allObs / 2; List <double> quints = new List <double>() { allObs / 5.0, 2.0 * allObs / 5.0, 3.0 * allObs / 5.0, 4.0 * allObs / 5.0 }; List <double> decs = new List <double>() { allObs / 10.0, 2.0 * allObs / 10.0, 3.0 * allObs / 10.0, 4.0 * allObs / 10.0, 5.0 * allObs / 10.0, 6.0 * allObs / 10.0, 7.0 * allObs / 10.0, 8.0 * allObs / 10.0, 9.0 * allObs / 10.0 }; int quintCoutner = 0, decCounter = 0; double obsCounter = 0; for (int i = 0; i < valueList[agg.GetName()].Count - 1; i++) // Count-1 limit is to prevent overflow if there are too few observations... { obsCounter += valueList[agg.GetName()][i][1]; if (findMedian && obsCounter >= halfObs) { results[DefPar.Totals.Varname_Median + agg.GetName()] = valueList[agg.GetName()][i][0]; findMedian = false; if (!findQuint && !findDec) { break; } } if (findQuint && obsCounter >= quints[quintCoutner]) { results[DefPar.Totals.Varname_Quintile + (quintCoutner + 1) + agg.GetName()] = obsCounter > quints[quintCoutner]? valueList[agg.GetName()][i][0] : (valueList[agg.GetName()][i][0] + valueList[agg.GetName()][i + 1][0]) / 2; quintCoutner++; if (quintCoutner >= quints.Count) { findQuint = false; } if (!findDec) { break; } } if (findDec && obsCounter >= decs[decCounter]) { results[DefPar.Totals.Varname_Decile + (decCounter + 1) + agg.GetName()] = obsCounter > decs[decCounter] ? valueList[agg.GetName()][i][0] : (valueList[agg.GetName()][i][0] + valueList[agg.GetName()][i + 1][0]) / 2; decCounter++; if (decCounter >= decs.Count) { break; } } } } } // finally put the results in all individuals foreach (HH hh in infoStore.hhAdmin.hhs) { for (int i = 0; i < hh.GetPersonCount(); i++) { foreach (ParVarIL agg in aggs) { foreach (string key in actions) { if (key != DefPar.Totals.Varname_Decile && key != DefPar.Totals.Varname_Quintile) { hh.SetPersonValue(results[key + agg.GetName()], totals[key + agg.GetName()].index, i); } else { for (int q = 1; q <= (key == DefPar.Totals.Varname_Decile ? 9 : 4); ++q) { string keyQ = key + q.ToString() + agg.GetName(); hh.SetPersonValue(results[keyQ], totals[keyQ].index, i); } } } } } } }
protected override void DoFunWork() { foreach (HH hh in infoStore.hhAdmin.hhs) { // we first gather all new persons to add them together at the end, to not preliminary change the HH List <List <double> > newPersons = new List <List <double> >(); double maxPersonId = 0; // find out the max-idPerson foreach (List <double> hhMem in hh.personVarList) { if (hhMem[indexIDPERSON] > maxPersonId) { maxPersonId = hhMem[indexIDPERSON]; } } // the dummy-HH-TU is necessary for evaluating the formuals and the HH_COND for adding "other" persons var dummyTU = hh.GetTUs(HHAdmin.DUMMY_HOUSEHOLD_TU)[0]; foreach (AddInstruction addInstruction in addInstructions) { if (addInstruction.addWho == DefPar.Value.ADDHHMEMBERS_CHILD || addInstruction.addWho == DefPar.Value.ADDHHMEMBERS_PARTNER) { for (byte p = 0; p < hh.GetPersonCount(); ++p) // there are as may children/partners added as there are { // "triggering" persons (i.e. persons fulfilling the condition) if (!addInstruction.cond.GetPersonValue(hh, new Person(p))) { continue; } // ADDING CHILDREN if (addInstruction.addWho == DefPar.Value.ADDHHMEMBERS_CHILD) { double motherId = -1, fatherId = -1; // with the id and gender of the "triggering" person we can set the first partent as either mother or father bool female = hh.personVarList[p][indexDGN] == 0; if (female) { motherId = hh.personVarList[p][indexIDPERSON]; } else { fatherId = hh.personVarList[p][indexIDPERSON]; } // if the partner of the first parent should be the other parent, we need to have the gender of the partner, // as a child can only have on mother and one father (due to have only idMother and idFather at our disposal) if (addInstruction.isPartnerParent) { double otherParentId = hh.personVarList[p][indexIDPARTNER]; if (otherParentId > 0) { bool?partnerFemale = null; foreach (List <double> hhMem in hh.personVarList) { if (hhMem[indexIDPERSON] == otherParentId) { partnerFemale = hhMem[indexDGN] == 0; } } if (partnerFemale != null && partnerFemale != female) { if (partnerFemale == true) { motherId = otherParentId; } else { fatherId = otherParentId; } } } } // once one or two parents are defined, the child can be added newPersons.Add(MakeNewPerson(hh, ++maxPersonId, dummyTU, addInstruction.varDefinitions, motherId, fatherId)); } // ADDING PARTNERS else { newPersons.Add(MakeNewPerson(hh, ++maxPersonId, dummyTU, addInstruction.varDefinitions, -1, -1, hh.personVarList[p][indexIDPERSON])); // the new person is the partner of the "triggering" person ... // ... but the "triggering" person is only the partner of the new person, if (s)he does not yet have a partner if (hh.personVarList[p][indexIDPARTNER] <= 0) { hh.personVarList[p][indexIDPARTNER] = maxPersonId; } } } } // ADDING OTHER PERSONS if (addInstruction.addWho == DefPar.Value.ADDHHMEMBERS_OTHER) { if (FunInSpineBase.IsCondMetByTU(hh, dummyTU, addInstruction.cond, DefPar.Value.WHO_ONE)) { newPersons.Add(MakeNewPerson(hh, ++maxPersonId, dummyTU, addInstruction.varDefinitions)); } } } foreach (List <double> newPerson in newPersons) { if (flagVar != null) { newPerson[flagVar.index] = 1; } hh.personVarList.Add(newPerson); List <string> stringVarList = new List <string>(nStringVars); for (int i = 0; i < nStringVars; ++i) { stringVarList.Add(string.Empty); } hh.personStringVarList.Add(stringVarList); } // taxunit definitions need to be updated (i.e. deleted and refreshed on next use) if (newPersons.Count > 0) { infoStore.hhAdmin.UpdateAllTUs(hh); } } }