parallel_structure.ts 15.19 KiB
import { Nub } from "../nub";
import { ParamCalculability } from "../param/param-definition";
import { Result } from "../util/result";
import { ParallelStructureParams } from "./parallel_structure_params";
import { Structure } from "./structure";
import { ParamDefinition } from "../param/param-definition";
import { IParamDefinitionIterator, ParamsEquation, ParamsEquationArrayIterator } from "../param/params-equation";
import { Props } from "../props";
import { Session } from "../session";
import { LinkedValue } from "../value_ref/object_ref";
import { loiAdmissiblesOuvrages, LoiDebit } from "./structure_props";
export { ParallelStructureParams };
/**
 * Interface pour mémoriser le n° d'ouvrage et le paramètre à calculer
interface IStructureVarCalc {
    index: number;
    prm: string;
/**
 * Calcul de une ou plusieurs structures hydrauliques en parallèles
 * reliées par les cotes amont et aval et dont le débit est égal à la
 * somme des débits de chaque structure.
export class ParallelStructure extends Nub {
    /** Tableau des structures hydrauliques en parallèle */
    protected _structures: Structure[] = [];
    /** getter only makes it kind of readonly */
    public get structures() {
        return this._structures;
    /**
     * paramètres castés au bon type
    get prms(): ParallelStructureParams {
        return this._prms as ParallelStructureParams;
    public getLoisAdmissibles(): { [key: string]: LoiDebit[]; } {
        return loiAdmissiblesOuvrages;
    /**
     * Mise à jour de Z1 pour toutes les structures en parallèle
    set Z1(Z1: number) {
        this.prms.Z1.v = Z1;
        this.updateStructuresH1H2();
    /**
     * Mise à jour de Z2 pour toutes les structures en parallèle
    set Z2(Z2: number) {
        this.prms.Z2.v = Z2;
        this.updateStructuresH1H2();
    /**
     * Itérateur sur tous les paramètres du Nub, plus tous les paramètres de
     * toutes les structures en parallèle
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
public get parameterIterator(): IParamDefinitionIterator { const prms: ParamsEquation[] = []; prms.push(this._prms); for (const st of this._structures) { prms.push(st.prms); } return new ParamsEquationArrayIterator(prms); } /** * Ajout d'une structure en parallèle * @param structure La structure à rajouter * @param after position après laquelle insérer la structure, à la fin sinon */ public addStructure(structure: Structure, after?: number) { if (after !== undefined) { this._structures.splice(after + 1, 0, structure); } else { this._structures.push(structure); } // add reference to parent collection (this) structure.parent = this; // propagate precision structure.prms.Pr.v = this.prms.Pr.v; } /** * remplace une structure hydraulique * @param index indice de la structure dans le tableau * @param structure nouvelle structure */ public replaceStructure(index: number, structure: Structure) { if (index > -1 && index < this._structures.length) { this._structures[index] = structure; } else { throw new Error(`ParallelStructure.replaceStructure invalid index ${index}`); } // add reference to parent collection (this) structure.parent = this; } /** * Finds oldStructure in the list, and replaces it (at the same index) with newStructure * @param oldStructure Structure to get the index for * @param newStructure Structure to set at this index */ public replaceStructureInplace(oldStructure: Structure, newStructure: Structure) { const index = this.getIndexForStructure(oldStructure); if (index === -1) { throw new Error("old Structure not found"); } this.replaceStructure(index, newStructure); } /** * Returns the current index of the given structure if any, * or else returns -1 * @param structure Structure to look for */ public getIndexForStructure(structure: Structure): number { let index: number = -1; for (let i = 0; i < this._structures.length; i++) { if (this._structures[i].uid === structure.uid) { index = i; } } return index; } /**
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
* @return true si la structure donnée est dans la liste */ public hasStructure(structure: Nub): boolean { return this.hasStructureUid(structure.uid); } /** * @return true si la structure donnée est dans la liste */ public hasStructureUid(structureUid: string): boolean { for (const s of this._structures) { if (s.uid === structureUid) { return true; } } return false; } /** * déplace une structure d'une position vers le début de la liste */ public moveStructureUp(structure: Structure) { let i = 0; for (const s of this._structures) { if (s.uid === structure.uid && i > 0) { const t = this._structures[i - 1]; this._structures[i - 1] = this._structures[i]; this._structures[i] = t; return; } i++; } } /** * déplace une structure d'une position vers la fin de la liste */ public moveStructureDown(structure: Structure) { let i = 0; for (const s of this._structures) { if (s.uid === structure.uid && i < this._structures.length - 1) { const t = this._structures[i]; this._structures[i] = this._structures[i + 1]; this._structures[i + 1] = t; return; } i++; } } /** * Supprime une structure hydraulique * @param index numéro de la structure dans le tableau */ public deleteStructure(index: number) { if (index > -1) { this._structures.splice(index, 1); } else { throw new Error("ParallelStructure.deleteStructure invalid index=" + index); } } /** * Calcul du débit des structures en parallèle (sans détail pour chaque structure) * @param sVarCalc Variable à calculer (Q uniquement) */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); this.updateStructuresH1H2(); return this.CalcQ();
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} /** * Calcul de la somme des débits de chaque structure * @param iExcept Index de la structure à ne pas additionner (optionel) */ public CalcQ(iExcept?: number): Result { if (iExcept !== undefined) { if (iExcept < 0 || iExcept >= this._structures.length) { throw new Error( "ParallelStructure.CalcQ iExcept not in [0;" + (this._structures.length - 1) + "]", ); } } const calcRes: Result = new Result(0); let qTot: number = 0; for (let i = 0; i < this._structures.length; i++) { if (i !== iExcept) { const res: Result = this._structures[i].Calc("Q"); calcRes.resultElement.AddResultElementToExtra(res.resultElement, `ouvrage[${i}].Q`); qTot += res.vCalc; } } // Assigne le débit total dans le résultat calcRes.resultElement.vCalc = qTot; return calcRes; } /** * Calcul du débit total, de la cote amont ou aval ou d'un paramètre d'une structure * @param sVarCalc Nom du paramètre à calculer : * "Q", "Z1", "Z2" ou "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre * @param rInit Valeur initiale */ public Calc(sVarCalc: string, rInit?: number): Result { let res: Result; switch (sVarCalc) { case "Z1": case "Z2": case "Q": res = super.Calc(sVarCalc, rInit); if (res.ok) { this.getParameter(sVarCalc).setValue(res.vCalc); } break; default: // Pour les caractéristiques des ouvrages const sVC = this.getStructureVarCalc(sVarCalc); res = this.CalcStructPrm(sVC, rInit); // Suppression des extraResults : ils sont complétés plus bas pour chaque ouvrage res.resultElement.extraResults = {}; if (res.ok) { this._structures[sVC.index].getParameter(sVC.prm).setValue(res.vCalc); } } if (res.ok) { // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires const resQtot: Result = this.CalcQ(); for (const extraResKey in resQtot.extraResults) { if (resQtot.extraResults.hasOwnProperty(extraResKey)) { res.resultElement.addExtraResult(extraResKey, resQtot.extraResults[extraResKey]); } } } this._result = res; return res; } /** * liste des valeurs (paramètre, résultat, résultat complémentaire) liables à un paramètre
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
* @param src paramètre auquel lier d'autres valeurs */ public getLinkableValues(src: ParamDefinition): LinkedValue[] { let res: LinkedValue[] = []; // linabkle parameters of this Nub, unless src comes from a child Structure if (! this.hasStructureUid(src.nubUid)) { res = super.getLinkableValues(src); } // paramètres liables des Nub structures enfants for (const s of this._structures) { const childStructureLinkableParams = s.getLinkableValues(src); res = res.concat(childStructureLinkableParams); } return res; } /** * Returns true if the computation of the current Nub requires, directly * or not, anything (parameter or result) from the given Nub UID "uid"; * includes checking child Structures if any * (to prevent circular linking) * @param uid */ public resultDependsOnNub(uid: string): boolean { let depends = super.resultDependsOnNub(uid); // does any of our child structures parameters depend on the target Nub ? if (! depends) { structuresloop: for (const s of this.structures) { if (s.resultDependsOnNub(uid)) { depends = true; break structuresloop; } } } return depends; } /** * Returns an object representation of the Nub's current state; compared to generic * Nub::objectRepresentation(), represents the parallel structures in a specific way * @param extra extra key-value pairs, for ex. calculator title in GUI */ public objectRepresentation(extra?: object) { let ret: any = { uid: this.uid, props: this.getPropertiesData(), }; if (extra) { ret = {...ret, ...{ meta: extra } }; // merge properties } // extend here to make "structures" and "parameters" the down-most keys ret = {...ret, ...{ structures: [], parameters: [] } }; // iterate over parameters const localParametersIterator = new ParamsEquationArrayIterator([this._prms]); for (const p of localParametersIterator) { if (p.visible) { ret.parameters.push(p.objectRepresentation()); } } // iterate over parallel structures for (const struct of this._structures) { ret.structures.push(struct.objectRepresentation()); } return ret; }
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
/** * Fills the current Nub with parameter values, provided an object representation * @param obj object representation of a Nub content (parameters, structures) */ public loadObjectRepresentation(obj: any) { // load regular Nub contents (parameters) super.loadObjectRepresentation(obj); // iterate over structures if any if (obj.structures && Array.isArray(obj.structures)) { for (const s of obj.structures) { // create the Nub const subNub = Session.getInstance().createNub(new Props(s.props), this); // try to keep the original ID if (! Session.getInstance().uidAlreadyUsed(s.uid)) { subNub.setUid(s.uid); } subNub.loadObjectRepresentation(s); // add Structure to parent this.addStructure(subNub as Structure); } } } /** * paramétrage de la calculabilité des paramètres */ protected setParametersCalculability() { this.prms.Q.calculability = ParamCalculability.EQUATION; this.prms.Z1.calculability = ParamCalculability.DICHO; this.prms.Z2.calculability = ParamCalculability.DICHO; } /** * Mise à jour de Z1, Z2, h1 et h2 pour tous les ouvrages */ protected updateStructuresH1H2() { for (const structure of this._structures) { structure.prms.Z1.v = this.prms.Z1.v; structure.prms.Z2.v = this.prms.Z2.v; structure.prms.update_h1h2(); } } /** * Renvoie le n° de structure et le paramètre à calculer * @param sVarCalc Nom du paramètre à calculer : "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre */ protected getStructureVarCalc(sVarCalc: string): IStructureVarCalc { let sIndex: string; let sPrm: string; if (sVarCalc.indexOf(".") === -1) { throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc}, (pas de la forme n.X)`); } [sIndex, sPrm] = sVarCalc.split("."); const i = parseInt(sIndex, 10); if (isNaN(i)) { throw new Error(`getStructureVarCalc() : erreur d'analyse de ${sVarCalc} (${sIndex} n'est pas un nombre)`); } return { index: i, prm: sPrm }; } /** * Calcul du paramètre d'un des ouvrages en parallèle * @param sVC Index de l'ouvrage et paramètre à calculer * @param rInit Valeur initiale */ protected CalcStructPrm(sVC: IStructureVarCalc, rInit?: number): Result { // Le débit restant sur la structure en calcul est : this._structures[sVC.index].prms.Q.setValue(this.prms.Q.v - this.CalcQ(sVC.index).vCalc);
421422423424425426427428429430431432433434435436437438439440441442
// Calcul du paramètre de la structure en calcul return this._structures[sVC.index].Calc(sVC.prm, rInit); } /** * Renvoie le n° de structure et le paramètre à calculer * @param sVarCalc Nom du paramètre à calculer : "ouvrage[n].X" avec "n" l'index de l'ouvrage et "X" son paramètre */ private getStructureVarCalc2(sVarCalc: string): IStructureVarCalc { const re = /([A-Z,a-z]+)\[(\d+)\]\.(.+)/; const match = re.exec(sVarCalc); if (match === null || match[1] !== "ouvrage") { throw new Error( `getStructureVarCalc2() : erreur d'analyse de ${sVarCalc}, (pas de la forme ouvrage[n].X)` ); } return { index: +match[2], prm: match[3] }; } }