An error occurred while loading the file. Please try again.
-
Guillaume Perréal authored6b9856f3
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}`);
}
}
}