private Dictionary <string, double> GetInternalFactorDefs() { // this is a somewhat simplified implementation, as I think it's an outdated concept and not used (and as such not worth the effort): // in the old executable the value of the factor can be a constant (and therewith also an uprating factor defined in the dialog) Dictionary <string, double> facDefs = new Dictionary <string, double>(StringComparer.OrdinalIgnoreCase); foreach (var group in GetParGroups(DefPar.Uprate.GROUP_FACTOR_DEF).Values) { ParBase pName = GetUniqueGroupPar <ParBase>(DefPar.Uprate.Factor_Name, group); ParNumber pNum = GetUniqueGroupPar <ParNumber>(DefPar.Uprate.Factor_Value, group); if (pName == null || pNum == null) { continue; // error (compulsory param missing ...) is issued in the general check } if (facDefs.ContainsKey(pName.xmlValue)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{description.Get()}: double definition of {DefPar.Uprate.Factor_Name} {pName.xmlValue}" }); } else { facDefs.Add(pName.xmlValue, pNum.GetValue()); // as said above, ignore the possibility of a constant } } return(facDefs); }
private bool CheckPrePost(ILSpecification ilSpecification, ParBase parPrefix, ParBase parPostfix, bool checkContent = true) { ilSpecification.prefix = parPrefix?.xmlValue ?? string.Empty; ilSpecification.postfix = parPostfix?.xmlValue ?? string.Empty; if (string.IsNullOrEmpty(ilSpecification.prefix) && string.IsNullOrEmpty(ilSpecification.postfix)) { return(true); // if no prefix or postfix is defined, then all vars match naming by definition. } if (!checkContent) { return(true); } foreach (string v in ParIL.GetILComponents(ilSpecification.ilName, infoStore.operandAdmin)) { if (v.StartsWith(ilSpecification.prefix, StringComparison.OrdinalIgnoreCase) && v.EndsWith(ilSpecification.postfix, StringComparison.OrdinalIgnoreCase)) { continue; } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: {ilSpecification.ilName}: contained variables must be named {GetFullVarName("*", ilSpecification)}; " + $"variable {v} does not follow this rule" }); return(false); } return(true); }
internal override void ProvideIndexInfo() { ParBase par = GetUniquePar <ParBase>(DefPar.Loop.Loop_Id); if (par == null) { return; // error is issued by standard-check } loopID = par.xmlValue; if (!EM_Helpers.IsValidName(loopID, out string illegal)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{par.description.Get()}: usage of illegal character(s): {illegal}" }); return; } infoStore.operandAdmin.indexLoopIDs.Add(loopID, this); // used by Store-function, for checking if loop exists infoStore.operandAdmin.RegisterVar(name: DefVarName.LOOPCOUNT + loopID, creatorFun: DefFun.Loop, description: description, isMonetary: false, isGlobal: true, // actually it is not global, as this would not work in parallel evironment // but by setting is Global to true, usage in RunCond is made possible isWriteable: false, // cannot be used as output-variable setInitialised: true); }
// this handles the old style syntax which puts the footnote outside the brackets in context with Amount, e.g. {xyz < amount}#1 // obviously, if the Calculator moves the footnotes inside, it's too late for Amount-replacement, // but if this would be the only problem one could think of changing the order // however the Calculator would produce {xyz#1 < amount#1} which is in the case I found wrong - there is no footnote for xyz // thus this would lead to the incorrect error message "missing footnote for xyz#1" // note that for e.g. {xyz < abc}#1, moving in is justified, because the programme never could know which side is meant // summarising: treating this as "special" is anyway necessary and thus it is done with this function private string HandleOldStyleAmount(string formula, FunBase fun) { string amount = DefPar.Value.AMOUNT.ToLower(); int amountIndex = formula.IndexOf(amount); while (amountIndex >= 0) { if (amountIndex == 0 || calc.IsSymbol(formula[amountIndex - 1])) // make sure not touching abc_amount { int footnoteIndex = formula.Substring(amountIndex).IndexOf("}#"); if (footnoteIndex == -1) { return(formula); // let Calculator catch the error } footnoteIndex += amountIndex + 1; // i.e. the # after the bracket string number = string.Empty; for (int i = footnoteIndex + 1; i < formula.Length; ++i) // start on character after the # { if ((formula[i] >= '0' && formula[i] <= '9') || (formula.ToLower()[i] >= 'a' && formula.ToLower()[i] <= 'z')) { number += formula[i]; } else { break; } } ParBase parAmount = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Amount, new List <string>() { number }); string replaceBy = "0"; if (parAmount != null) { replaceBy = parAmount.xmlValue; } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: missing footnote {DefPar.Footnote.Amount}({number})" }); } // if there is actually a second footnote (except #_Amount) with the same number, do not delete the footnote // allows for e.g. {yem < amount}#1, with #_Amount(1) = 12000#y and #_Level(1) = tu_whatsoever if (fun.GetFootnoteParCount(number) == 1) { formula = formula.Remove(footnoteIndex, number.Length + 1); } formula = formula.Remove(amountIndex, amount.Length); formula = formula.Insert(amountIndex, replaceBy); } amountIndex = formula.IndexOf(amount, amountIndex + 1); } return(formula); }
protected override void PrepareNonCommonPar() { ParBase parFileName = GetUniquePar <ParBase>(DefPar.DefOutput.File); if (parFileName != null) // if null the programme is stopped after reading parameters (missing compulsory parameter) { fileName = Path.Combine(infoStore.runConfig.pathOutput, parFileName.xmlValue); if (!fileName.ToLower().EndsWith(".txt")) { fileName += ".txt"; } if (infoStore.runConfig.stdOutputFilenameSuffix != string.Empty) // e.g. uk_2017_std -> uk_2017_BTAoff { AdaptFileNameForNonStdExtensionSwitches(infoStore.runConfig.stdOutputFilenameSuffix); } if (infoStore.runConfig.outFileDate != string.Empty) // e.g. hu_2017_std.txt -> hu_2017_std_201805301954.txt { fileName = fileName.Insert(fileName.Length - 4, "_" + infoStore.runConfig.outFileDate); } // * * * T O D O * * * // check at this point if file is ready for writting, i.e. valid file-name, not used by another file, ... // to avoid running the whole thing and then cannot write (probably requires try-catch on attempt to open) // also if the file is available, lock it now? } // in future probably replaced by Scale function, but currently still needed, in particular for PET ParFormula parMultipleMonetaryBy = GetUniquePar <ParFormula>(DefPar.DefOutput.MultiplyMonetaryBy); if (parMultipleMonetaryBy != null) { multiplyMonetaryBy = parMultipleMonetaryBy.GetGlobalValue(); } PrepareVarILPar(); PrepareDefILPar(); PrepareUnitInfoPar(); append = GetParBoolValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.Append); suppressVoidMessage = GetParBoolValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.Suppress_Void_Message); nDecimals = (int)GetParNumberValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.nDecimals); formatDecimals = "0."; for (int i = 0; i < nDecimals; i++) { formatDecimals += "#"; } parWho = GetUniquePar <ParCateg>(DefPar.Common.Who_Must_Be_Elig); parEligVar = GetUniquePar <ParVar>(DefPar.Common.Elig_Var); ParNumber parReplaceUnitLoopVoidBy = GetUniquePar <ParNumber>(DefPar.DefOutput.Replace_Void_By); if (parReplaceUnitLoopVoidBy != null) { doReplaceUnitLoopVoidBy = true; replaceUnitLoopVoidBy = parReplaceUnitLoopVoidBy.GetValue(); } }
protected void PrepareStartEndPar() { // assess parameters which define start and end of loop loopStart = GetStartEnd(DefPar.Loop.First_Pol, DefPar.Loop.First_Func, DefPar.Loop.Start_After_Pol, DefPar.Loop.Start_After_Func, true); loopEnd = GetStartEnd(DefPar.Loop.Last_Pol, DefPar.Loop.Last_Func, DefPar.Loop.Stop_Before_Pol, DefPar.Loop.Stop_Before_Func, false); StartEnd GetStartEnd(string parNamePol, string parNameFun, string parNameNeighbourPol, string parNameNeighbourFun, bool start) { ParBase parPol = GetUniquePar <ParBase>(parNamePol); ParBase parFun = GetUniquePar <ParBase>(parNameFun); ParBase parNeighbourPol = GetUniquePar <ParBase>(parNameNeighbourPol); ParBase parNeighbourFun = GetUniquePar <ParBase>(parNameNeighbourFun); StartEnd se = new StartEnd() { infoStore = infoStore, description = description, isStart = start }; int defCnt = 0; if (parPol != null) { se.ident = parPol.xmlValue; se.isFun = false; se.isNeighbour = false; ++defCnt; } if (parFun != null) { se.ident = parFun.xmlValue; se.isFun = true; se.isNeighbour = false; ++defCnt; } if (parNeighbourPol != null) { se.ident = parNeighbourPol.xmlValue; se.isFun = false; se.isNeighbour = true; ++defCnt; } if (parNeighbourFun != null) { se.ident = parNeighbourFun.xmlValue; se.isFun = true; se.isNeighbour = true; ++defCnt; } string sse = parNamePol == DefPar.Loop.First_Pol ? "start" : "end"; if (defCnt > 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: over-definition for loop {sse}" }); } if (defCnt == 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: missing definition for loop {sse}" }); } return(se); } }
private bool PreparePostPar() { ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Store.PostLoop); ParBase parPostFix = GetUniquePar <ParBase>(DefPar.Store.PostFix); if (parPostLoop == null && parPostFix == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: neither {DefPar.Store.PostFix} nor {DefPar.Store.PostLoop} defined" }); return(false); } if (parPostLoop != null && parPostFix != null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: unclear specification - both {DefPar.Store.PostFix} and {DefPar.Store.PostLoop} defined" }); return(false); } if (parPostLoop != null) { post = parPostLoop.xmlValue; if (!infoStore.operandAdmin.indexLoopIDs.ContainsKey(post)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parPostLoop.description.Get()}: no loop with {DefPar.Loop.Loop_Id} = {post} found" }); return(false); } storeType = infoStore.operandAdmin.indexLoopIDs[post] is FunUnitLoop ? STORETYPE.UNITLOOP : STORETYPE.LOOP; } else { post = parPostFix.xmlValue; storeType = STORETYPE.FIX; if (!EM_Helpers.IsValidName(post, out string illegal)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parPostFix.description.Get()}: usage of illegal character(s): {illegal}" }); return(false); } } return(true); }
private bool GetFromTo(ParBase parFromTo, out List <int> iterations) // not activated (see above) { iterations = new List <int>(); string from = string.Empty, to = string.Empty; if (!parFromTo.xmlValue.Contains('-')) { from = parFromTo.xmlValue; } else { string[] ft = parFromTo.xmlValue.Split('-'); if (ft.Count() < 2) { return(SyntaxError()); } from = ft[0]; to = ft[1]; } if (!int.TryParse(from, out int f)) { return(SyntaxError()); } int t = f; if (to != string.Empty && !int.TryParse(to, out t)) { return(SyntaxError()); } if (f > t) { return(SyntaxError($"from ({f}) > to ({t})")); } if (f <= 0) { return(SyntaxError($"from ({f}) must not be zero or negative")); } for (int i = f; i <= t; ++i) { iterations.Add(i); } return(true); bool SyntaxError(string explanation = "correct syntax: e.g. 1-3") { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parFromTo.description.Get()}: invalid range of loop-iterations: {explanation}" }); return(false); } }
internal override void CheckAndPrepare(FunBase fun, List <string> footnoteNumbers) { ParBase parDatabase = fun.GetFootnotePar <ParBase>(DefQuery.Par.DataBasename, footnoteNumbers); if (parDatabase != null) { isUsedDB = infoStore.IsUsedDatabase(parDatabase.xmlValue) == true ? 1.0 : 0.0; } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: compulsory query-parameter {DefQuery.Par.DataBasename} missing" }); } }
private string HandleAmount(string formula, FunBase fun) { string amount = DefPar.Value.AMOUNT.ToLower() + "#"; int amountIndex = formula.IndexOf(amount); while (amountIndex >= 0) { if (amountIndex == 0 || !calc.IsVarChar(formula[amountIndex - 1])) // make sure not touching abc_amount#1 { string number = string.Empty; for (int i = amountIndex + amount.Length; i < formula.Length; ++i) { if ((formula[i] >= '0' && formula[i] <= '9') || (formula.ToLower()[i] >= 'a' && formula.ToLower()[i] <= 'z')) { number += formula[i]; } else { break; } } ParBase parAmount = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Amount, new List <string>() { number }); string replaceBy = "0"; if (parAmount != null) { replaceBy = parAmount.xmlValue; } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: missing footnote {DefPar.Footnote.Amount}({number})" }); } formula = formula.Remove(amountIndex, amount.Length + number.Length); formula = formula.Insert(amountIndex, replaceBy); } amountIndex = formula.IndexOf(amount, amountIndex + 1); } return(formula); }
private double GetAddMod(ParBase par) { string addMode = par.xmlValue.Trim(); // i.e. '+' or '-' or '+0.5' or ... if (addMode == "+" || addMode == "-") { addMode += "1"; } if (!double.TryParse(EM_Helpers.AdaptDecimalSign(addMode), out double am)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{par.description.Get()}: invalid incomelist add-mode: {addMode}" }); } return(am); }
protected override void PrepareNonCommonPar() { updateAll = GetParBoolValueOrDefault(DefFun.UpdateTu, DefPar.UpdateTu.Update_All); if (!updateAll) { ParBase parName = GetUniquePar <ParBase>(DefPar.UpdateTu.Name); if (parName != null) { tuName = parName.xmlValue; } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: paramter {DefPar.UpdateTu.Name} not defined" }); } } }
protected override void PreprocessParameters() { if (GetParGroups(DefPar.DefIl.GROUP_REGEXP).Count == 0) { return; } Dictionary <string, double> regExVar = new Dictionary <string, double>(); foreach (var group in GetParGroups(DefPar.DefIl.GROUP_REGEXP).Values) { ParBase parDef = GetUniqueGroupPar <ParBase>(DefPar.DefIl.RegExp_Def, group); ParBase parFactor = GetUniqueGroupPar <ParBase>(DefPar.DefIl.RegExp_Factor, group); if (parDef == null) { continue; } string pattern = parDef.xmlValue; double addMode = parFactor == null ? 1.0 : GetAddMod(parFactor); foreach (string matchVar in infoStore.operandAdmin.GetMatchingVar(pattern: pattern, regExpr: true)) { if (!regExVar.ContainsKey(matchVar)) { regExVar.Add(matchVar, addMode); } } } infoStore.operandAdmin.AddRegExVarToILContent(GetUniquePar <ParBase>(DefPar.DefIl.Name).xmlValue, regExVar); // note wrt using PreprocessParameters-function instead of ReplaceVarNameByIndex-function (as FunUprate does): // the latter comes after CheckAndPrepare, thus ParIL would do its work first and ignore the additional content of the IL // thus variables defined after this DefIL (with DefVar) are not taken into account // // note on differences to "normal" (i.e. placeholder) incomelist entries: // - because of the above described, RegExp-entries are evaluted when the DefL appears in spine and not, as "normal" entries, on first usage of the incomelist // - only "registered" variables are taken into account, that means if a variable exists in data and is described in the variables file, but not // used by any function before the DefIL, it is ignored (while a "normal" entry would register such a variable) // uprating would however already count as usage (and one anyway gets a warning, if a data-variable is not uprated) // (if this turns out to be a problem, we can improve later) // // this differnt behaviour can be justified, because this is a different parameter, I guess ... }
// note that at this stage parameters are available (via GetxxxPar-functions of FunBase) // but not yet prepared, i.e. only xmlValue is available internal override void ProvideIndexInfo() { ParBase parName = GetUniquePar <ParBase>(DefPar.DefIl.Name); if (parName == null) { return; } Dictionary <string, double> content = new Dictionary <string, double>(); foreach (var part in GetPlaceholderPar <ParBase>()) { string varILName = part.Key; content.Add(varILName, GetAddMod(part.Value)); // note that vars/ILs are 'registered' (i.e.a.o. checked) in ParIL.CheckAndPrepare (i.e. on 1st use) } ParBool parWarn = GetUniquePar <ParBool>(DefPar.DefIl.Warn_If_NonMonetary); bool warnIfNonMon = parWarn == null?DefinitionAdmin.GetParDefault <bool>(DefFun.DefIl, DefPar.DefIl.Warn_If_NonMonetary) : ParBool.IsTrue(parWarn.xmlValue); // note: GetParBoolValueOrDefault cannot be used as parameter WarnIfNonMon is not yet checked infoStore.operandAdmin.RegisterIL(parName.xmlValue, DefFun.DefIl, description, content, warnIfNonMon); }
internal bool IsProspectiveLoopOperand(string operand) // see InfoStore.IsProspectiveStoreOperand for description { // note that this can be called before (or after) PrepareNonCommonPar, therefore one cannot rely on variables (e.g. post, storeType, ...) // also note that we are only looking for the "running" operands, e.g. yem_loop, ils_earns_loop (i.e. without an iteration) ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Store.PostLoop); if (parPostLoop == null) { return(false); // most likely a PostFix-Store, thus not relevant } foreach (ParVar par in GetNonUniquePar <ParVar>(DefPar.Store.Var)) { if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } } foreach (ParIL par in GetNonUniquePar <ParIL>(DefPar.Store.IL)) { // first check for IL itself, e.g. ils_earns_loop string ili = ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue); if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } // then check for the content, e.g. yem_loop, yse_loop if (!infoStore.operandAdmin.Exists(par.xmlValue)) { continue; // only check if il is already registered } foreach (string ilVar in ParIL.GetILComponents(par.xmlValue, infoStore.operandAdmin)) { if (ComposeStoreName(ilVar, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } } } return(false); }
public static void PrintParInfo() { RandColor.WriteLine(Environment.NewLine + "parameter-order (140011-12) or function-order (140011) for analysis, x to exit", colorHeading); do { RandColor.Write("order: ", GetSwapColor()); string o = Console.ReadLine(); if (o == "x") { break; } string fo, parOrder; fo = o.Contains("-") ? o.Substring(0, o.IndexOf('-')) : o; parOrder = o.Contains("-") ? o.Substring(o.IndexOf('-')).TrimStart(new char[] { '-' }) : string.Empty; if (!double.TryParse(fo, out double funOrder) || !infoStore.spine.ContainsKey(funOrder)) { continue; } if (parOrder == string.Empty) { foreach (var p in infoStore.spine[funOrder].TestGetAllPar(true)) { RandColor.WriteLine($"{p.description.GetParName()} {p.description.par.order}", GetSwapColor()); } continue; } ParBase anaPar = GetPar(funOrder, parOrder); if (anaPar != null) { PrintParDetails(anaPar); } RandColor.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - ", colorHeading); } while (true); ParBase GetPar(double funOrder, string parOrder) { return((from p in infoStore.spine[funOrder].TestGetAllPar(true) where p.description.par.order == parOrder select p).FirstOrDefault()); } }
/// <summary> /// checks if the standard footnote-parameters, i.e. #_LowLim, #_UpLim, #_Level, are applied on the parameter /// if so, stores them in lowLim, upLim and alternativeTU (see above) /// also provides the "cleaned" value (e.g. yem#1 -> yem) /// note that the footnote-parameters are assessed via the (mother)function (parameter fun) /// also note that the only other (not here handled) footnote-parameters are 'amount', which is handled by ParFormula /// and query parameters which will not issue a "missing" (see below) but let the query check if it can use the footnote /// </summary> protected void ExtractStandardFootnotes(string value, out string cleanedValue, FunBase fun) { List <string> numbers = GetFootnoteNumbers(value, out cleanedValue); // it's unlikely, but yem#1#3 is possible (see GetFootnoteNumbers) if (numbers.Count == 0) { return; // no footnotes } // limits (see remark in _FunInSpineBase_Lim wrt not using a common implementation for limits) pLowLim = fun.GetFootnotePar <ParFormula>(DefPar.Footnote.LowLim, numbers); if (pLowLim != null) { if (pLowLim.IsGlobal(true)) { lowLim = pLowLim.GetGlobalValue(); pLowLim = null; } else { doRunTimeLimCheck = true; } } pUpLim = fun.GetFootnotePar <ParFormula>(DefPar.Footnote.UpLim, numbers); if (pUpLim != null) { if (pUpLim.IsGlobal(true)) { upLim = pUpLim.GetGlobalValue(); pUpLim = null; } else { doRunTimeLimCheck = true; } } ParCateg pLimpriority = fun.GetFootnotePar <ParCateg>(DefPar.Footnote.LimPriority, numbers); if (pLimpriority != null) { limPri = pLimpriority.GetCateg(); } if (!doRunTimeLimCheck) // both limits available (might be double.MinValue and/or double.MaxValue, but does no harm here) { CheckLimits(ref lowLim, ref upLim); } // alternative TU ParBase parAltTU = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Level, numbers); if (parAltTU != null) { alternativeTU = parAltTU.xmlValue; } // if none of the standard footnotes is defined in the function #x points to nowhere ... if (GetType() == typeof(ParQuery)) // ... except for queries, which may have own footnotes { return; // (this is slightly negligent, as it accepts e.g. IsMarried#1 without respective footnote-parameter) } if (pLowLim == null && lowLim == double.MinValue && pUpLim == null && upLim == double.MaxValue && parAltTU == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{description.Get()}: missing footnote parameter for {value}" }); } }
protected override void PrepareNonCommonPar() { if (!IsRunCondMet()) { return; } infoStore.applicableUprateFunctions.Add(description); // to allow for checking if there is no/more than one applicable Uprate // get the "function-internal" (rather outdated) factor definitions, i.e. those defined by parameters Factor_Name/Factor_Value Dictionary <string, double> internalFactorDefs = GetInternalFactorDefs(); // check if DBYearVar exists and handle accordingly ParVar parDBYearVarPar = GetUniquePar <ParVar>(DefPar.Uprate.DBYearVar); isDBYearVarUsed = parDBYearVarPar != null && parDBYearVarPar.name != DefPar.Value.NA; if (isDBYearVarUsed) { if (parDBYearVarPar.name.Trim() != string.Empty) { infoStore.operandAdmin.CheckRegistration(name: parDBYearVarPar.name.Trim(), isOutVar: false, warnIfNotInit: false, description: parDBYearVarPar.description); if (!infoStore.operandAdmin.GetVarExistsInPersonVarList(parDBYearVarPar.name)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parDBYearVarPar.description.Get()}: Parameter {DefPar.Uprate.DBYearVar} was used with value '{parDBYearVarPar.name}', but this variable is not defined" }); } else { DBYearVar = parDBYearVarPar.name; } } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{this.description.Get()}: Parameter {DefPar.Uprate.DBYearVar} was used and left empty" }); } } // (1) "NORMAL" VARIABLES: // an uprating-group consists of the variable to uprate (e.g. yem=$f_cpi) and optionally of a condition (e.g. Factor_Cond={dgn=0}) foreach (var group in GetParGroups(DefPar.Uprate.GROUP_MAIN).Values) { // optional condition parameter ParCond parCond = GetUniqueGroupPar <ParCond>(DefPar.Uprate.Factor_Condition, group); // compulsory var-name/factor-parameter (e.g. yem (in policy-column) / $f_cpi (in system-column)) // usually this will be one placeholder-parameter but it is possible that one condition applies to several variables List <ParBase> listParMain = GetPlaceholderGroupPar <ParBase>(group); if (listParMain.Count == 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parCond.description.Get()}: loose condition {parCond.xmlValue}" }); continue; } foreach (ParBase parMain in listParMain) { string upVarName = parMain.description.GetParName(); // get the name of the variable to uprate (e.g. yem) // check for double uprating, but take care of conditions, e.g. twice yem-uprating without condition -> warning, yem-uprating different for men and women -> ok bool exists = ExistsUpVar(upVarName, out bool conditioned); if (exists && (!conditioned || parCond == null)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parMain.description.Get()}: double uprating of variable {upVarName}" }); } Dictionary <double, double> upFactors = GetFactors(internalFactorDefs, parMain); upVars.Add(new UpVar() { varSpec = new VarSpec() { name = upVarName }, factors = upFactors, parCondition = parCond }); // the main purpose of this registration is to ensure the variable exists (an error is issued if not) // in fact uprated variables are likely to be registered by usage (why uprate a variable that is not used?) // (it could still be that an uprated but otherwise unused variable should be in the output and would not if VarGroup is used) infoStore.operandAdmin.CheckRegistration(name: upVarName, isOutVar: false, warnIfNotInit: false, description: parMain.description); } } // check for double conditioned uprating foreach (UpVar condUpVar in from cuv in upVars where cuv.parCondition != null select cuv) { if ((from cuv in upVars where upVars.IndexOf(cuv) > upVars.IndexOf(condUpVar) && cuv.varSpec.name.ToLower() == condUpVar.varSpec.name.ToLower() && cuv.parCondition != null && cuv.parCondition.description.GetParGroup() == condUpVar.parCondition.description.GetParGroup() select cuv).Count() > 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{condUpVar.parCondition.description.Get()}: double uprating of variable {condUpVar.varSpec.name}" }); } } // (2) AGGREGATE VARIABLES: // the group consists of AggVar_Name (the agg-var to uprate) and a list of AggVar_Part (the vars summing up to the agg-var) // and optionally of AggVar_Tolerance (a tolerance for the check if part-vars actually sum up to agg-var) foreach (var group in GetParGroups(DefPar.Uprate.GROUP_AGG).Values) { ParVar parName = GetUniqueGroupPar <ParVar>(DefPar.Uprate.AggVar_Name, group); if (parName == null) { continue; // error is issued by general checking } if (ExistsUpVar(parName.name, out bool dummy)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parName.description.Get()}: double uprating of variable {parName.name} (aggregate and normally)" }); } ParNumber parTol = GetUniqueGroupPar <ParNumber>(DefPar.Uprate.AggVar_Tolerance, group); AggUpVar aggUpVar = new AggUpVar() { varSpec = new VarSpec() { name = parName.name } }; if (parTol != null) { aggUpVar.tolerance = parTol.GetValue(); } foreach (ParVar parPart in GetNonUniqueGroupPar <ParVar>(DefPar.Uprate.AggVar_Part, group)) { aggUpVar.parts.Add(new VarSpec() { name = parPart.name }); } if (aggUpVar.parts.Count > 0) { aggUpVars.Add(aggUpVar); } } // (3) VARIABLES DEFINED BY REGULAR EXPRESSION (e.g. for updating expenditure variables) foreach (var group in GetParGroups(DefPar.Uprate.GROUP_REGEXP).Values) { ParBase parDef = GetUniqueGroupPar <ParBase>(DefPar.Uprate.RegExp_Def, group); ParBase parFactor = GetUniqueGroupPar <ParBase>(DefPar.Uprate.RegExp_Factor, group); if (parDef == null || parFactor == null) { continue; } upRegExp.Add(parDef.xmlValue, GetFactors(internalFactorDefs, parFactor)); } // get default factor ... ParBase parDefFac = GetUniquePar <ParBase>(DefPar.Uprate.Def_Factor); if (parDefFac != null) { defaultFactor = GetFactors(internalFactorDefs, parDefFac); } // ... and the optional parameter WarnIfNoFactor warnIfNoFactor = GetParBoolValueOrDefault(DefFun.Uprate, DefPar.Uprate.WarnIfNoFactor); // ... and the optional parameter WarnIfNonMonetary warnIfNonMonetary = GetParBoolValueOrDefault(DefFun.Uprate, DefPar.Uprate.WarnIfNonMonetary); if (zeroFactorSysCollector.Count > 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{description.Get()}: uprating-index for system year is 0 for {string.Join(", ", zeroFactorSysCollector)}, resulting in uprating concerned variables by 0." }); } if (zeroFactorDataCollector.Count > 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{description.Get()}: uprating-index for data year is 0 for {string.Join(", ", zeroFactorDataCollector)}, resulting in setting concerned variables to NaN." }); } }
protected override void PrepareNonCommonPar() { aggs = GetNonUniquePar <ParVarIL>(DefPar.Totals.Agg); if (aggs.Count == 0) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: missing required parameter AGG" }); return; } foreach (string t in new List <string> { DefPar.Totals.Varname_Sum, DefPar.Totals.Varname_Mean, DefPar.Totals.Varname_Median, DefPar.Totals.Varname_Decile, DefPar.Totals.Varname_Quintile, DefPar.Totals.Varname_Count, DefPar.Totals.Varname_PosCount, DefPar.Totals.Varname_NegCount, DefPar.Totals.Varname_Min, DefPar.Totals.Varname_Max }) { ParBase par = GetUniquePar <ParBase>(t); if (par == null) { continue; } actions.Add(t); foreach (ParVarIL agg in aggs) { string aggName = agg.GetName(); agg.CheckAndPrepare(this); int n = 1; if (t == DefPar.Totals.Varname_Decile) { n = 9; } if (t == DefPar.Totals.Varname_Quintile) { n = 4; } for (int i = 1; i <= n; ++i) { string counter = t == DefPar.Totals.Varname_Decile || t == DefPar.Totals.Varname_Quintile ? i.ToString() : string.Empty; string varName = $"{par.xmlValue}{counter}_{aggName}"; infoStore.operandAdmin.RegisterVar( // generate the variable that will take the total name: varName, creatorFun: DefFun.Totals, description: par.description, isMonetary: false, // not really clear, but adding over TU does not make sense isGlobal: true, // equal for each person isWriteable: false, // cannot be use as output-variable setInitialised: true); if (infoStore.operandAdmin.Exists(varName)) { totals.Add(t + (n > 1 ? i.ToString() : "") + aggName, new VarSpec() { name = varName }); } } } } // setup booleans hasMedian = actions.Contains(DefPar.Totals.Varname_Median); hasQuint = actions.Contains(DefPar.Totals.Varname_Quintile); hasDec = actions.Contains(DefPar.Totals.Varname_Decile); hasSum = actions.Contains(DefPar.Totals.Varname_Sum); hasMean = actions.Contains(DefPar.Totals.Varname_Mean); // check if there is a condition for inclusion ParCond inclCond = GetUniquePar <ParCond>(DefPar.Totals.Incl_Cond); if (inclCond != null) { ParCateg inclWho = GetUniquePar <ParCateg>(DefPar.Totals.Incl_Cond_Who); string inclWhoVal = (inclWho == null) ? DefPar.Value.WHO_ALL : inclWho.GetCateg(); include = new Tuple <ParCond, string>(inclCond, inclWhoVal); } // check if results should be weighted useWeights = GetParBoolValueOrDefault(DefFun.Totals, DefPar.Totals.Use_Weights); if (useWeights) // get the weight var, if null use dwt { ParVar dwtPar = GetUniquePar <ParVar>(DefPar.Totals.Weight_Var); dwtName = dwtPar != null ? dwtPar.name : DefVarName.DWT; infoStore.operandAdmin.CheckRegistration(dwtName, false, false, description); } // }
protected override void PrepareNonCommonPar() { if (!IsRunCondMet()) // note that this works for info that is clearly available at read-time, e.g. {IsUsedDatabase} or {1} { return; // but simply returns true for global variables, which may (in theory) change over run-time } // to handle the latter IsRunCond is called again in the Run-function (see below) // consequently for e.g. {0} the variables are not even generated // while for {$Const}, with $Const=0 at the point of request, the variables exist but are set to 0 // this also reflects the behaviour of the old executable ParBase parSysYear = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_SystemYear : DefPar.DefVar.Var_SystemYear); if (parSysYear != null && !EM_Helpers.DoesValueMatchPattern(parSysYear.xmlValue, infoStore.country.sys.year)) { return; } ParBase parDataSet = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_Dataset : DefPar.DefVar.Var_Dataset); if (parDataSet != null && !infoStore.IsUsedDatabase(parDataSet.xmlValue)) { return; } foreach (var g in GetParGroups(isConst ? DefPar.DefConst.THE_ONLY_GROUP : DefPar.DefVar.THE_ONLY_GROUP)) { List <ParBase> group = g.Value; // global variables (DefConst) allow for parameter Condition (but there is no reason why it wouldn't work for DefVar as well, thus no check) ParCond cond = GetUniqueGroupPar <ParCond>(DefPar.DefConst.Condition, group); List <ParFormula> initFormulas = GetPlaceholderGroupPar <ParFormula>(group); if (initFormulas.Count == 0) // there can be single Monetary parameters if definition is n/a for this system { continue; } if (cond == null && initFormulas.Count > 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{initFormulas[0].description.Get()}: multiple definition, group {g.Key} is already in use" }); continue; } foreach (ParFormula initFormula in initFormulas) { string varName = initFormula.description.GetParName(); if (!EM_Helpers.IsValidName(varName, out string illegal)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{initFormula.description.Get()}: name contains illegal character(s) '{illegal}'" }); continue; } if (isConst && cond == null && !initFormula.IsGlobal()) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{initFormula.description.Get()}: trying to initialise global variable with a non-global amount" }); } bool isMonetary = false; if (!isConst) // variables defined with DefConst cannot be monetary (more precisely, should not be added over TUs) { // if monetary-parameter is defined, use it, otherwise monetary=true (more precisely, get the default value from lib-def) ParBool parMonetary = GetUniqueGroupPar <ParBool>(DefPar.DefVar.Var_Monetary, group); isMonetary = parMonetary != null?parMonetary.GetBoolValue() : DefinitionAdmin.GetParDefault <bool>(funName: DefFun.DefVar, parName: DefPar.DefVar.Var_Monetary); } if (!infoStore.operandAdmin.Exists(varName)) // double definition is not illegal (maybe questionable, but handled like this in old exe) { infoStore.operandAdmin.RegisterVar(name: varName, creatorFun: DefFun.DefVar, description: initFormula.description, isMonetary: isMonetary, isGlobal: isConst && cond == null, isWriteable: true, // DefVar defined variables can be used as output-var (this is a bit lax with DefConst) setInitialised: true); // DefVar defined variables always have an initial value - // if user sets it n/a it does not exist, otherwise she needs to assign a value // actual initialisation is done in the Run function if (!infoStore.operandAdmin.Exists(varName)) { continue; // registration failed } } else if (infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefVar && infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefConst) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()} {varName}: {DefFun.DefVar}/{DefFun.DefConst} can only overwrite variables created by (another) {DefFun.DefVar}/{DefFun.DefConst}" }); continue; } // variable cannot yet be initialised, as at this stage the hh-data does not exist (no formula interpretation possible yet) // note on still setting the variable initialised at this stage, in context with the "not-initialised" warning: // parameters are prepared in the spine-order, thus parameters which are prepared before would get a "not known" // and parameters prepared afterwards are "legal" users if (!varDefs.ContainsKey(varName)) { varDefs.Add(varName, new List <VarDef>()); // see definition of varDefs for reason for Dictionary } varDefs[varName].Add(new VarDef() { varSpec = new VarSpec() { name = varName }, initFormula = initFormula, condition = cond, groupNo = g.Key }); } } // a variable can only be defined more than once within one function, if it is conditioned: // only one definition can exist without a condition (which will be used as the default fallback value if conditions also exist) foreach (List <VarDef> condConstDef in varDefs.Values) { if (condConstDef.Count > 1 && (from c in condConstDef where c.condition == null select c).Count() > 1) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: multiple definitions of {condConstDef[0].varSpec.name} without {DefPar.DefConst.Condition} found" }); } } }
protected override void PrepareNonCommonPar() { ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Restore.PostLoop); ParBase parPostFix = GetUniquePar <ParBase>(DefPar.Restore.PostFix); if (parPostLoop == null && parPostFix == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: neither {DefPar.Restore.PostFix} nor {DefPar.Restore.PostLoop} defined" }); return; } if (parPostLoop != null && parPostFix != null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: unclear specification - both {DefPar.Restore.PostFix} and {DefPar.Restore.PostLoop} defined" }); return; } string post = parPostLoop == null ? parPostFix.xmlValue : parPostLoop.xmlValue; if (!infoStore.operandAdmin.indexStoreFuns.ContainsKey(post)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: no related Store-function ({post}) found" }); return; } relatedStore = infoStore.operandAdmin.indexStoreFuns[post]; switch (relatedStore.storeType) { case FunStore.STORETYPE.UNITLOOP: infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: restoring UnitLoop values is not possible" }); return; case FunStore.STORETYPE.FIX: if (parPostFix == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parPostLoop.description.Get()}: related Store-function concerns {DefPar.Store.PostFix}" }); return; } break; case FunStore.STORETYPE.LOOP: if (parPostLoop == null) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parPostFix.description.Get()}: related Store-function concerns {DefPar.Store.PostLoop}" }); return; } break; } if (parPostLoop != null) { ParNumber parIteration = GetUniquePar <ParNumber>(DefPar.Restore.Iteration); if (parIteration != null) { loopIteration = parIteration.GetValue(); if (!EM_Helpers.IsNonNegInteger(loopIteration, false)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parIteration.description.Get()}: must be a non-negative integer" }); } else { relatedStore.RegisterOperands((int)loopIteration); // see description in FunStore } } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: parameter {DefPar.Restore.Iteration} missing" }); } } }
private static void PrintParDetails(ParBase par) { RandColor.WriteLine(par.description.Get(), GetSwapColor()); RandColor.WriteLine($"xml-value: {par.xmlValue}", GetSwapColor()); if (infoStore.hhAdmin == null) { return; } HH dummyHH = infoStore.hhAdmin.GetFirstHH(); List <Person> dummyTU = new List <Person>() { new Person(0) }; if (par.GetType() == typeof(ParBool)) { RandColor.WriteLine($"value: {(par as ParBool).GetBoolValue()}", GetSwapColor()); } else if (par.GetType() == typeof(ParCateg)) { RandColor.WriteLine($"value: {(par as ParCateg).GetCateg()}", GetSwapColor()); } else if (par.GetType() == typeof(ParNumber)) { RandColor.WriteLine($"value: {(par as ParNumber).GetValue()}", GetSwapColor()); } else if (par.GetType() == typeof(ParTU)) { string tuName = (par as ParTU).name; dummyHH.GetTUs(tuName); // that's to "use" the TU, i.e. to create it for the HH RandColor.WriteLine($"TU {tuName} has {dummyHH.hhTUs[tuName].Count} unit(s) in 1st HH", GetSwapColor()); } else if (par.GetType() == typeof(ParVar)) { RandColor.WriteLine($"value: {(par as ParVar).GetValue(dummyHH, dummyTU)}", GetSwapColor()); } else if (par.GetType() == typeof(ParOutVar)) // there is actually nothing to check, out-vars just care for registration { RandColor.WriteLine($"index: {(par as ParOutVar).index}", GetSwapColor()); } else if (par.GetType() == typeof(ParIL)) { RandColor.WriteLine($"value: {(par as ParIL).GetValue(dummyHH, dummyTU)}", GetSwapColor()); } else if (par.GetType() == typeof(ParVarIL)) { RandColor.WriteLine($"value: {(par as ParVarIL).GetValue(dummyHH, dummyTU)}", GetSwapColor()); } else if (par.GetType() == typeof(ParFormula)) { RandColor.WriteLine($"value: {(par as ParFormula).GetValue(dummyHH, dummyTU)}", GetSwapColor()); } else if (par.GetType() == typeof(ParCond)) { RandColor.WriteLine($"ParCond not yet handled", ConsoleColor.DarkMagenta); } else { RandColor.WriteLine($"unknow type: {par.GetType()}", GetSwapColor()); } }
/// <summary> /// try to identify parameters and, if valid, generate the respective ParXXX and put into respective lists (see above) /// </summary> private void ClassifyParameters(Dictionary <string, ExeXml.Par> xmlParList, DefinitionAdmin.Fun funDef) { int dummyGroupNumber = -9999; // this is for placeholder-parameters, see below foreach (var xmlPar in xmlParList) { Description parDescription = new Description(description, xmlPar.Value, xmlPar.Key); string xmlParName = xmlPar.Value.Name; // first check if it is an 'ordinary' parameter ... DefinitionAdmin.Par parDef = funDef.GetParDef(xmlParName); if (parDef != null) { string officialParName = funDef.GetOfficalParName(xmlParName); // is (in contrast to xmlParName) case-sensitive and // corresponds to constants as defined in Common-library // generate parameter ... ParBase par = GeneratePar(xmlPar, parDef, parDescription); // ... and put it into the list it belongs too ... if (parDef.isFootnote) // ... footnote-list { if (GetGroupNumber(xmlPar.Value, parDescription, out int dummy)) { if (!footnotePar.ContainsKey(xmlPar.Value.Group)) { footnotePar.Add(xmlPar.Value.Group, new Dictionary <string, ParBase>()); } if (!footnotePar[xmlPar.Value.Group].ContainsKey(officialParName)) { footnotePar[xmlPar.Value.Group].Add(officialParName, par); } else { ReportDoubleDef(parDescription); } } } else if (parDef.maxCount == 1) // ... unique-parameter-list { if (!uniquePar.ContainsKey(officialParName)) { uniquePar.Add(officialParName, par); if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group)) { ReportUselessGroup(parDescription); } } else { ReportDoubleDef(parDescription); } } else // ... non-unique-parameter-list { if (!nonUniquePar.ContainsKey(officialParName)) { nonUniquePar.Add(officialParName, new List <ParBase>()); } nonUniquePar[officialParName].Add(par); if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group)) { ReportUselessGroup(parDescription); } } continue; } // ... if not successuful, check if it is a group parameter ... parDef = funDef.GetGroupParDef(xmlParName, out string groupName); if (parDef != null) { if (GetGroupNumber(xmlPar.Value, parDescription, out int groupNo)) { // generate parameter ... ParBase par = GeneratePar(xmlPar, parDef, parDescription); // ... and put it into group-parameter-list if (!groupPar.ContainsKey(groupName)) { groupPar.Add(groupName, new SortedList <int, List <ParBase> >()); } if (!groupPar[groupName].ContainsKey(groupNo)) { groupPar[groupName].Add(groupNo, new List <ParBase>()); } if (parDef.maxCount > 1 || GetUniqueGroupPar <ParBase>(xmlPar.Value.Name, groupPar[groupName][groupNo]) == null) { groupPar[groupName][groupNo].Add(par); } else { ReportDoubleDef(parDescription); } } continue; } // ... if still not successful, it could still be placehoder parameter ... if (funDef.AllowsForPlaceholders()) { parDef = funDef.GetPlaceholderDef(out string phGroupName); ParBase par = GeneratePar(xmlPar, parDef, parDescription, true); if (phGroupName == null) // non-group placeholder, as e.g. in SetDefault, DefIL { if (!placeholderPar.TryAdd(xmlParName, par)) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: {xmlParName} double definition (is ignored)" }); } } else // group placeholder, as e.g. in DefVar (PH, IsGlobal, IsMonetary), Uprate (PH, FactorCond) { GetGroupNumber(xmlPar.Value, parDescription, // note that this returns a dummy-group if the user didn't indicate one out int groupNo, true); // as placeholders only actually need a group if they are "further specified" (e.g. uprating-factors: factor_condition) if (!groupPar.ContainsKey(phGroupName)) { groupPar.Add(phGroupName, new SortedList <int, List <ParBase> >()); } if (!groupPar[phGroupName].ContainsKey(groupNo)) { groupPar[phGroupName].Add(groupNo, new List <ParBase>()); } groupPar[phGroupName][groupNo].Add(par); } continue; } // ... now we give up infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: unknown parameter" }); } if (infoStore.runConfig.warnAboutUselessGroups) { foreach (var groupType in groupPar) { if (groupType.Key.ToLower() == DefPar.SchedCalc.Band_XXX.ToLower()) { continue; } foreach (var group in groupType.Value) { if (group.Key >= 0 && group.Value.Count == 1) { ReportUselessGroup(group.Value[0].description); } } } } // internal function for generating parameters ParBase GeneratePar(KeyValuePair <string, ExeXml.Par> xmlPar, DefinitionAdmin.Par parDef, Description parDescription, bool isPlaceholder = false) { ParBase par; switch (parDef.valueType) { case DefPar.PAR_TYPE.FORMULA: par = new ParFormula(infoStore); break; case DefPar.PAR_TYPE.CONDITION: par = new ParCond(infoStore); break; case DefPar.PAR_TYPE.BOOLEAN: par = new ParBool(infoStore); break; case DefPar.PAR_TYPE.NUMBER: par = new ParNumber(infoStore); break; case DefPar.PAR_TYPE.TEXT: par = new ParBase(infoStore); break; case DefPar.PAR_TYPE.VAR: par = new ParVar(infoStore); break; case DefPar.PAR_TYPE.OUTVAR: par = new ParOutVar(infoStore); break; case DefPar.PAR_TYPE.IL: par = new ParIL(infoStore); break; case DefPar.PAR_TYPE.TU: par = new ParTU(infoStore); break; case DefPar.PAR_TYPE.VARorIL: par = new ParVarIL(infoStore); break; case DefPar.PAR_TYPE.CATEG: par = new ParCateg(infoStore, parDef.categValues); break; case DefPar.PAR_TYPE.PLACEHOLDER: par = new ParBase(infoStore); break; default: throw new Exception($"Not yet properly implemented parameter value type {parDef.valueType}"); } par.description = parDescription; par.xmlValue = xmlPar.Value.val; par.description.isPlaceholder = isPlaceholder; return(par); } bool GetGroupNumber(ExeXml.Par p, Description parDescription, out int groupNumber, bool allowDummy = false) { groupNumber = dummyGroupNumber++; // placeholders (e.g.uprating factors) only actually need a group if (string.IsNullOrEmpty(p.Group)) // if they are "further specified" (e.g.factor_condition) { if (allowDummy) { return(true); } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: missing group" }); return(false); } if (int.TryParse(p.Group, out groupNumber)) { return(true); } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: invalid group {p.Group} (must be an integer number)" }); return(false); } void ReportDoubleDef(Description parDescription) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $" {parDescription.Get()}: defined more than once" }); } void ReportUselessGroup(Description parDescription) { if (parDescription.GetFunName() != DefFun.Store) // add a special exception for Store, as it has its own reporting { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $" {parDescription.Get()}: group has no use" }); } } }
private Dictionary <double, double> GetFactors(Dictionary <string, double> internalFactorDefs, ParBase parFac) { Dictionary <double, double> allFactors = new Dictionary <double, double>(); string upFactorS = parFac.xmlValue; // xmlValue contains the uprating instruction, // which may be a number (e.g. 1.4) or the name of a factor (e.g. $f_cpi) if (!double.TryParse(EM_Helpers.AdaptDecimalSign(upFactorS), out double upFactor)) // first try if a number ... { if (internalFactorDefs.ContainsKey(upFactorS)) // ... then try if a factor defined by Factor_Name/Factor_Value { allFactors.Add(UpVar.ALLYEARS, internalFactorDefs[upFactorS]); } else if (infoStore.country.upFacs.ContainsKey(upFactorS)) // ... then try if a factor-name defined in dialog { if (infoStore.country.upFacs[upFactorS].Get(infoStore.country.sys.year, out double sysInd)) { if (sysInd == 0 && !zeroFactorSysCollector.Contains(upFactorS)) { zeroFactorSysCollector.Add(upFactorS); } if (isDBYearVarUsed) { // Calculate the uprating factors foreach (KeyValuePair <string, double> facs in infoStore.country.upFacs[upFactorS].GetAll()) { if (double.TryParse(facs.Key, out double yr)) { if (facs.Value == 0 && !zeroFactorDataCollector.Contains(facs.Key)) { zeroFactorDataCollector.Add(facs.Key); } allFactors.Add(yr, sysInd / facs.Value); } else { // This should only happen if a year cannot be parsed - This should NEVER happen! infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parFac.description.Get()}: invalid year '{facs.Key}' found in uprating factors!" }); return(allFactors); } } } else { if (infoStore.country.upFacs[upFactorS].Get(infoStore.country.data.year, out double dbInd)) { if (dbInd == 0 && !zeroFactorDataCollector.Contains(upFactorS)) { zeroFactorDataCollector.Add(upFactorS); } allFactors.Add(UpVar.ALLYEARS, sysInd / dbInd); } else { // Or keep 1 and return warning if any indices are missing string dataInfo = string.IsNullOrEmpty(infoStore.country.data.year) ? $": income-year is missing for '{infoStore.country.data.Name}'" : $" for data year '{infoStore.country.data.year}'"; infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parFac.description.Get()}: insufficient definition of uprating-factor '{parFac.xmlValue}'{dataInfo} (1 is used as default)" }); } } } else { // Or keep 1 and return warning if any indices are missing infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, message = $"{parFac.description.Get()}: insufficient definition of uprating-factor '{parFac.xmlValue}' for system year '{infoStore.country.sys.year}' (1 is used as default)" }); } } else { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{parFac.description.Get()}: unknown factor {parFac.xmlValue}" }); } } else { allFactors.Add(UpVar.ALLYEARS, upFactor); } return(allFactors); }