nub.ts 12.31 KiB
import { Debug } from "./base";
import { Dichotomie } from "./dichotomie";
import { ComputeNode } from "./compute-node";
import { Result } from "./util/result";
import { ParamValues } from "./param/param-values";
import { ParamValueMode } from "./param/param-value-mode";
import { ParamDefinition } from ".";
import { IReferencedNub } from "./value_ref/object_ref";
/**
 * Classe abstraite de Noeud de calcul : classe de base pour tous les calculs
export abstract class Nub extends ComputeNode implements IReferencedNub {
    private _dichoStartIntervalMaxSteps: number = 100;
    /**
     * résultat de Calc()/CalcSerie()
    protected _result: Result;
     * paramétrage de la dichotomie
    /**
     * étapes de recherche de l'intervalle de départ
    set dichoStartIntervalMaxSteps(n: number) {
        this._dichoStartIntervalMaxSteps = n;
    /**
     * Formule utilisée pour le calcul analytique (solution directe ou méthode de résolution spécifique)
    public abstract Equation(sVarCalc: string): Result;
    /**
     * Calcul d'une équation quelque soit l'inconnue à calculer
     * @param sVarCalc nom de la variable à calculer
     * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie
     * @param rPrec précision de calcul
    public Calc(sVarCalc: string, rInit?: number, rPrec: number = 0.001): Result {
        const computedVar = this.getParameter(sVarCalc);
        if (rInit === undefined) {
            rInit = computedVar.v;
        if (computedVar.isAnalytical()) {
            this._result = this.Equation(sVarCalc);
            this._result.name = sVarCalc;
            return this._result;
        const resSolve: Result = this.Solve(sVarCalc, rInit, rPrec);
        if (!resSolve.ok) {
            this._result = resSolve;
            this._result.name = sVarCalc;
            return this._result;
        const sAnalyticalPrm: string = this.getFirstAnalyticalParameter().symbol;
        computedVar.setValue(resSolve.vCalc);
        const res: Result = this.Equation(sAnalyticalPrm);
        res.vCalc = resSolve.vCalc;
        this._result = res;
        this._result.name = sVarCalc;
        return res;
    /**
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* effectue une série de calculs sur un paramètre * @param rPrec précision de calcul * @param rInit solution approximative du paramètre * @param sDonnee éventuel symbole du paramètre à calculer */ public CalcSerie(rPrec: number = 0.001, rInit?: number, sDonnee?: string): Result { let variatedParam: ParamDefinition; let computedParam: ParamDefinition; let prmValue: ParamValues; // instance de ParamValues utilisée pour le paramètre varié (qui peut être un paramètre référencé (importé)) for (const p of this.parameterIterator) { switch (p.valueMode) { case ParamValueMode.SINGLE: break; case ParamValueMode.LISTE: case ParamValueMode.MINMAX: if (variatedParam == undefined) { variatedParam = p; prmValue = p.paramValues; } else throw new Error(`CalcSerie() : il y plusieurs paramètres à varier (au moins ${variatedParam.symbol} et ${p.symbol})`); break; case ParamValueMode.CALCUL: if (sDonnee == undefined) { if (computedParam == undefined) computedParam = p; else throw new Error(`CalcSerie() : il y plusieurs paramètres à calculer (au moins ${computedParam.symbol} et ${p.symbol})`); } break; case ParamValueMode.LINK: if (p.referencedParamValues !== undefined) switch (p.referencedParamValues.valueMode) { case ParamValueMode.SINGLE: break; case ParamValueMode.LISTE: case ParamValueMode.MINMAX: if (variatedParam == undefined) { variatedParam = p; prmValue = p.referencedParamValues; } else throw new Error(`CalcSerie() : il y plusieurs paramètres à varier (au moins ${variatedParam.symbol} et ${p.symbol})`); break; case ParamValueMode.CALCUL: if (sDonnee == undefined) { if (computedParam == undefined) computedParam = p; else throw new Error(`CalcSerie() : il y plusieurs paramètres à calculer (au moins ${computedParam.symbol} et ${p.symbol})`); } break; default: throw new Error(`CalcSerie() : valeur référencée de ParamValueMode ${ParamValueMode[p.referencedParamValues.valueMode]} non prise en charge`); } break; default: throw new Error(`CalcSerie() : valeur de ParamValueMode ${ParamValueMode[p.valueMode]} non prise en charge`); } } if (sDonnee)
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
var computedSymbol: string = sDonnee; else { if (computedParam == undefined) throw new Error(`CalcSerie() : aucun paramètre à calculer`); computedSymbol = computedParam.symbol; } if (rInit === undefined) rInit = computedParam.v; if (variatedParam == undefined) this._result = this.Calc(computedSymbol, rInit, rPrec); // résultat dans this._result else { const res = new Result(); prmValue.initIterator(); while (prmValue.hasNext) { prmValue.next; this.Calc(computedSymbol, rInit, rPrec); // résultat dans this._result if (this._result.ok) { res.addResultElement(this._result.resultElement); res.addLog(this._result.log); rInit = this._result.resultElement.vCalc; } res.globalLog.addLog(this._result.globalLog); } this._result = res; } this._result.name = computedSymbol; return this._result; } /** * Résoud l'équation par une méthode numérique * @param sVarCalc nom de la variable à calculer * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie * @param rPrec précision de calcul */ private Solve(sVarCalc: string, rInit: number, rPrec: number): Result { const dicho: Dichotomie = new Dichotomie(this, sVarCalc, this.DBG); dicho.startIntervalMaxSteps = this._dichoStartIntervalMaxSteps; const target = this.getFirstAnalyticalParameter(); return dicho.Dichotomie(target.v, rPrec, rInit); } public get result(): Result { return this._result; } // interface IReferencedNub public getReferencedParamValues(desc: string): ParamValues { return this.getParameter(desc).paramValues; } public getReferencedResult(desc?: string): Result { if (desc === undefined || (this._result !== undefined && this._result.name === desc)) return this._result; return this.CalcSerie(0.001, 0.1, desc); // il y a des valeurs par défaut pour la précision et la valeur initiale, mais il faudra prévoir un mécanisme pour les transmettre } public getReferencedExtraResult(desc: string): any { const tmp: string[] = desc.split("."); const r: Result = this.getReferencedResult(tmp[0]); return r.getExtraResult(tmp[1]); } public getReferencedValuesIterator(desc: string): IterableIterator<number> { const tmp = desc.split(".");
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
if (tmp.length > 1 && tmp[1] === "") if (this._result !== undefined && this._result.name === tmp[0]) return this._result.valuesIterator; const p = this.getParameter(desc); switch (p.paramValues.valueMode) { case ParamValueMode.SINGLE: case ParamValueMode.MINMAX: case ParamValueMode.LISTE: return p.paramValues.valuesIterator; case ParamValueMode.CALCUL: return this.getReferencedResult(desc).valuesIterator; case ParamValueMode.LINK: throw new Error(`Nub.getReferencedValuesIterator() : mode de valeur ${ParamValueMode[p.paramValues.valueMode]} invalide pour le paramètre référencé par ${desc}`); } } /** * @returns liste des paramètres liables à un paramètre * @param p paramètre qui sert de clé de recherche des paramètres liables */ // public getLinkableParameters(param: ParamDefinition): any[] { // const res: any[] = []; // for (const p of this._prms) // if (p.uid !== param.uid) // switch (p.valueMode) { // case ParamValueMode.SINGLE: // case ParamValueMode.MINMAX: // case ParamValueMode.LISTE: // switch (param.symbol) { // case "Z1": // case "Z2": // if (p.symbol === "Z1" || p.symbol === "Z2") // res.push({ "param": p, "nub": this }); // break; // default: // if (p.symbol === param.symbol) // res.push({ "param": p, "nub": this }); // } // } // return res; // } private addPrefix(str: string, prefix: string) { return prefix === undefined ? str : `${prefix}${str}`; } /** * liste des valeurs (paramètre, résultat, résultat complémentaire) liables à un paramètre * @param src objet qui sert de clé de recherche des paramètres liables, de type INamedObject | string * @returns tableau d'objets de la forme { "name":string, "value":NamedIterableValues, "nub":Nub}, nub=Nub d'origine de la "value" */ public getLinkableValues(src: any, prefix?: string): any[] { const res: any[] = []; const isStr = typeof (src) === "string"; const name = isStr ? src : src.name; const hasUid = isStr ? false : "uid" in src; // paramètres for (const p of this._prms) { const cond = hasUid ? p.uid !== src.uid : true; // pour éviter d'ajouter le paramètre d'entrée dans le tableau résultat if (cond)
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
switch (p.valueMode) { case ParamValueMode.SINGLE: case ParamValueMode.MINMAX: case ParamValueMode.LISTE: switch (name) { case "Z1": case "Z2": if (p.symbol === "Z1" || p.symbol === "Z2") res.push({ "name": this.addPrefix(p.symbol, prefix), "value": p, "nub": this }); break; default: if (p.symbol === name) res.push({ "name": this.addPrefix(p.symbol, prefix), "value": p, "nub": this }); } } } // résultat if (this._result !== undefined) { if (this._result.name === name) res.push({ "name": this.addPrefix(`${name}.`, prefix), "value": this._result, "nub": this }); // résultats complémentaires const erIter = this._result.getIterableExtraResults(name) if (erIter !== undefined) res.push({ "name": this.addPrefix(`${this._result.name}.${name}`, prefix), "value": erIter, "nub": this }); } return res; } }