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
     }
 }
Exemple #4
0
        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);
                }
            }
        }