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 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); } } }