nub.ts 11.77 KiB
import { ParamDefinition, ParamsEquation } from ".";
import { ComputeNode } from "./compute-node";
import { Dichotomie } from "./dichotomie";
import { INamedIterableValues, INumberIterator, IterableValues } from "./param/param-value-iterator";
import { ParamValueMode } from "./param/param-value-mode";
import { ParamValues } from "./param/param-values";
import { Props } from "./props";
import { Result } from "./util/result";
import { IReferencedNub } from "./value_ref/object_ref";
/**
 * Classe abstraite de Noeud de calcul dans une session :
 * classe de base pour tous les calculs
export abstract class Nub extends ComputeNode implements IReferencedNub {
    /** paramétrage de la dichotomie */
    public dichoStartIntervalMaxSteps: number = 100;
    /** résultat de Calc()/CalcSerie() */
    protected _result: Result;
    private _props: Props;
    public get result(): Result {
        return this._result;
    public get properties() {
        return this._props;
    // originally in SessionNub
    public set properties(props: Props | {}) {
        const params = props instanceof Props ? props : new Props(props);
        this._props = params.clone();
    /**
     * 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 quelle que 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);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
res.vCalc = resSolve.vCalc; this._result = res; this._result.name = sVarCalc; return res; } /** * 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 computedParam: ParamDefinition; // instance de ParamValues utilisée pour le paramètre varié (qui peut être un paramètre référencé (importé)) let variatedValues: IterableValues; for (const p of this.parameterIterator) { if (p.valueMode === ParamValueMode.CALCUL) { if (sDonnee === undefined) { if (computedParam === undefined) { computedParam = p; } else { // tslint:disable-next-line:max-line-length throw new Error(`CalcSerie() : il y plusieurs paramètres à calculer (au moins ${computedParam.symbol} et ${p.symbol})`); } } } switch (p.valueMode) { case ParamValueMode.SINGLE: break; case ParamValueMode.LISTE: case ParamValueMode.MINMAX: variatedValues = this.setVariatedValues(p, variatedValues); break; case ParamValueMode.CALCUL: // Le paramètre lié est un résultat de calcul if (p.isReferenceDefined && p.referencedResult.nbResultElements > 1) { variatedValues = this.setVariatedValues(p, variatedValues); } break; case ParamValueMode.LINK: const ro = p.referencedObject; if (ro !== undefined && ro.hasMultipleValues) { variatedValues = this.setVariatedValues(p, variatedValues); } break; default: // tslint:disable-next-line:max-line-length throw new Error(`CalcSerie() : valeur de ParamValueMode ${ParamValueMode[p.valueMode]} non prise en charge`); } } let computedSymbol: string; if (sDonnee) { computedSymbol = sDonnee; } else { if (computedParam === undefined) { throw new Error(`CalcSerie() : aucun paramètre à calculer`); } computedSymbol = computedParam.symbol; } if (rInit === undefined) { rInit = computedParam.v;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} if (variatedValues === undefined) { this._result = this.Calc(computedSymbol, rInit, rPrec); // résultat dans this._result } else { const res = new Result(); variatedValues.initValuesIterator(false); while (variatedValues.hasNext) { // tslint:disable-next-line:no-unused-expression variatedValues.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; } // interface IReferencedNub public getReferencedParamValues(desc: string): ParamValues { const prm = this.getParameter(desc); if (prm !== undefined) { return prm.paramValues; } return undefined; } public getReferencedResult(desc?: string): Result { if (desc === undefined || (this._result !== undefined && this._result.name === desc)) { return this._result; } // 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 return this.CalcSerie(0.001, 0.1, desc); } 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): INumberIterator { const ro = this.getReferencedObject(desc); return ro.valuesIterator; } public getReferencedObject(desc: string): INamedIterableValues { const tmp = desc.split("."); if (tmp.length === 1) { // paramètre (ex "Q") return this.getParameter(desc); } if (tmp[1] === "") { // résultat (ex "Q.") if (this._result !== undefined) { return this._result; } }
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
// les autres objets référençables n'implémentant pas IJalhydObject... return undefined; } /** * 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 * @param excludeResult true si on veut exclure des valeurs retournées le résultat/résultat complémentaire * correspondant à la clé de recherche * @returns tableau d'objets de la forme { "name":string, "value":INamedIterableValues, "nub":Nub}, * nub=Nub d'origine de la "value" * * l'étiquette "name" (cf. INubReference.defineReference) est de la forme <n | ouvrage[n] | N1>[.[N2]] * n : indice de de l'ouvrage dans le cas des ouvrages parallèles * N1 : un nom de paramètre/résultat (dans le cas d'un résultat, il est suivi d'un point) * N2 : nom de résultat complémentaire (optionnel) * ex : * Q, Z1 (paramètres) * J. (résultat) * .Yf (résultat complémentaire du résultat courant) * Q.Yf (résultat complémentaire du résultat nommé "Q") * 0.Q : paramètre Q du 1er ouvrage (ouvrages parallèles) * ouvrage[1].Q_Mode : résultat complémentaire du 2ème ouvrage (ouvrages parallèles) */ public getLinkableValues(src: any, prefix?: string, excludeResult: boolean = false): 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) { // pour éviter d'ajouter le paramètre d'entrée dans le tableau résultat const cond = hasUid ? p.uid !== src.uid : true; if (cond) { 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 && !excludeResult) { 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 });
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
} } return res; } /** * 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); } private addPrefix(str: string, prefix: string) { return prefix === undefined ? str : `${prefix}${str}`; } private setVariatedValues(newValues: INamedIterableValues, oldValues: IterableValues) { if (oldValues === undefined) { return newValues; } else { // tslint:disable-next-line:max-line-length throw new Error(`CalcSerie() : Paramètres à varier redondant : ${newValues.name}`); } } }