jet.ts 10.29 KiB
import { CalculatorType } from "../compute-node";
import { Nub } from "../nub";
import { ParamCalculability, ParamFamily } from "../param/param-definition";
import { ParamValueMode } from "../param/param-value-mode";
import { Message, MessageCode } from "../util/message";
import { Result } from "../util/result";
import { JetParams } from "./jet_params";
export class Jet extends Nub {
    /** steps for generating the trajectory */
    protected precision = 50;
    public constructor(prms: JetParams, dbg: boolean = false) {
        super(prms, dbg);
        this._calcType = CalculatorType.Jet;
        this._defaultCalculatedParam = prms.D;
        this.resetDefaultCalculatedParam();
    /** paramètres castés au bon type */
    get prms(): JetParams {
        return this._prms as JetParams;
    public Calc(sVarCalc: string, rInit?: number): Result {
        this.currentResult = super.Calc(sVarCalc, rInit);
        // omit extra results if calculation failed
        if (this.result.vCalc !== undefined) {
            // H: chute
            this.result.resultElement.values.H = this.prms.ZJ.v - this.prms.ZW.v;
            // Y: profondeur
            this.result.resultElement.values.Y = this.prms.ZW.v - this.prms.ZF.v;
            // YH: rapport profondeur/chute
            this.result.resultElement.values.YH = this.result.resultElement.values.Y / this.result.resultElement.values.H;
            // t: temps de vol
            this.result.resultElement.values.t = this.prms.D.V / Math.cos(this.alpha) / this.prms.V0.V;
            // Vx: vitesse horizontale à l'impact
            this.result.resultElement.values.Vx = this.prms.V0.V * Math.cos(this.alpha);
            // Vz: vitesse verticale à l'impact
            this.result.resultElement.values.Vz =
                this.prms.V0.V * Math.sin(this.alpha) - this.result.resultElement.values.t * 9.81;
            // Vt: vitesse à l'impact
            this.result.resultElement.values.Vt = Math.sqrt(
                Math.pow(this.result.resultElement.values.Vx, 2)
                + Math.pow(this.result.resultElement.values.Vz, 2)
        let ZF = this.prms.ZF.v;
        let ZW = this.prms.ZW.v;
        let ZJ = this.prms.ZJ.v;
        if (this.calculatedParam === this.prms.ZF) {
            ZF = this.result.resultElement.vCalc;
        if (this.calculatedParam === this.prms.ZW) {
            ZW = this.result.resultElement.vCalc;
        if (this.calculatedParam === this.prms.ZJ) {
            ZJ = this.result.resultElement.vCalc;
        // y a-t-il de l'eau au dessus du sol ?
        if (ZF > ZW) {
            this.result.resultElement.log.add(new Message(MessageCode.WARNING_JET_WATER_ELEVATION_UNDERGROUND));
        // le jet est-il bien au dessus du sol ?
        if (ZF > ZJ) {
            this.result.resultElement.log.add(new Message(MessageCode.WARNING_JET_START_ELEVATION_UNDERGROUND));
        // le jet est-il bien émergé ?
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
if (ZW > ZJ) { this.result.resultElement.log.add(new Message(MessageCode.WARNING_JET_START_SUBMERGED)); } return this.result; } public Equation(sVarCalc: string): Result { const g: number = 9.81; let v: number; let h: number; switch (sVarCalc) { case ("ZJ"): h = this.CalcH(); v = h + this.prms.ZW.v; break; case ("ZW"): h = this.CalcH(); v = this.prms.ZJ.v - h; break; case ("D"): h = (this.prms.ZJ.v - this.prms.ZW.v); const sqrtArg = Math.pow(this.prms.V0.v * Math.sin(this.alpha), 2) + 2 * g * h; if (sqrtArg < 0) { return new Result(new Message(MessageCode.ERROR_JET_SUBMERGED_NO_SOLUTION), this); } v = this.prms.V0.v / g * Math.cos(this.alpha) * ( this.prms.V0.v * Math.sin(this.alpha) + Math.sqrt(sqrtArg) ); break; default: throw new Error("Jet.Equation() : invalid variable name " + sVarCalc); } return new Result(v); } /** clone casting */ public clone(): Jet { return super.clone() as Jet; } /** * Returns an array of trajectories built from the current Nub state. * A trajectory is a list of coordinate pairs representing the fall height (y), * for each abscissa (x) between 0 and the impact abscissa (D). * A coordinate pair is a list of 2 numbers [ x, y ]. * If no parameter is varying, result will contain only 1 element. * Trajectory calculation uses a copy of the current Nub to calculate ZW from D. */ public generateTrajectories(): number[][][] { const trajectories: number[][][] = []; // clone Nub so that ZW calculation will not impact current state const nub = this.clone(); // is anything varying ? if (this.resultHasMultipleValues()) { const valuesLists: any = {}; const length = this.variatingLength(); // reset clone params to SINGLE mode nub.prms.V0.valueMode = ParamValueMode.SINGLE; nub.prms.S.valueMode = ParamValueMode.SINGLE; nub.prms.D.valueMode = ParamValueMode.SINGLE;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
// H will be calculated // 1. find all extended values lists; ignore ZW (will be calculated) and D (will be reaffected) for (const symbol of [ "S", "V0", "ZJ" ]) { const p = this.getParameter(symbol); valuesLists[symbol] = []; if (this.calculatedParam.symbol === symbol) { // calculated for (let i = 0; i < length; i++) { valuesLists[symbol].push(this.result.resultElements[i].vCalc); } } else if (p.hasMultipleValues) { // variating const iter = p.getExtendedValuesIterator(length); while (iter.hasNext) { const nv = iter.next(); valuesLists[symbol].push(nv.value); } } else { // single for (let i = 0; i < length; i++) { valuesLists[symbol].push(p.singleValue); } } } // 2. build one series for each variating step for (let i = 0; i < length; i++) { // exclude iteration if calculation has failed if (this.result.resultElements[i].ok) { // set clone params values; ignore ZW (will be calculated) // and D (will be reaffected by getDAbscissae) for (const symbol of [ "S", "V0", "ZJ" ]) { const val = valuesLists[symbol][i]; nub.getParameter(symbol).v = val; } // compute series trajectories.push(this.buildSeriesForIteration(nub, i)); } else { // mark failed calculation using empty list trajectories.push([]); } } } else { // nothing is varying for (const symbol of [ "S", "V0", "ZJ" ]) { // init .v of clone nub.getParameter(symbol).v = nub.getParameter(symbol).singleValue; } trajectories.push(this.buildSeriesForIteration(nub, 0)); } return trajectories; } protected CalcH(): number { const g: number = 9.81; return ( 0.5 * g * Math.pow(this.prms.D.v, 2) / (Math.pow(Math.cos(this.alpha), 2) * Math.pow(this.prms.V0.v, 2) ) - Math.tan(this.alpha) * this.prms.D.v); } /** * Build a trajectory data series for a calculation iteration */ protected buildSeriesForIteration(nub: Jet, i: number): number[][] { const traj: number[][] = []; const xs = this.getDAbscissae(i); for (const x of xs) { // compute H for D = x nub.prms.D.v = x; // console.log("__computing H for x =", x, nub.prms.D.v);
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
const h = nub.Calc("ZW"); traj.push([ x, h.vCalc ]); } return traj; } /** * Returns a list of abscissae from 0 to D (number of steps is this.precision) * @param variatingIndex if D is variating, index of the D value to fetch */ protected getDAbscissae(variatingIndex: number = 0): number[] { const abs: number[] = []; // divide impact abscissa into steps let D: number; if (this.calculatedParam.symbol === "D") { D = this.result.resultElements[variatingIndex].vCalc; } else if (this.prms.D.hasMultipleValues) { const length = this.variatingLength(); const valsD: number[] = []; const iter = this.prms.D.getExtendedValuesIterator(length); while (iter.hasNext) { const nv = iter.next(); valsD.push(nv.value); } D = valsD[variatingIndex]; } else { D = this.prms.D.V; } const step = D / this.precision; // zero-abscissa let x = 0; abs.push(x); // abscissae in ]0,D[ for (let i = 0; i < this.precision - 1; i++) { x += step; abs.push(x); } // D-abscissa abs.push(D); return abs; } protected setParametersCalculability() { this.prms.V0.calculability = ParamCalculability.DICHO; this.prms.S.calculability = ParamCalculability.DICHO; this.prms.ZJ.calculability = ParamCalculability.EQUATION; this.prms.ZW.calculability = ParamCalculability.EQUATION; this.prms.ZF.calculability = ParamCalculability.FIXED; this.prms.D.calculability = ParamCalculability.EQUATION; } protected exposeResults() { this._resultsFamilies = { H: ParamFamily.TOTALFALLS, Y: ParamFamily.HEIGHTS, YH: undefined, t: undefined, Vx: undefined, Vz: undefined, Vt: undefined }; } private get alpha(): number { return Math.atan(this.prms.S.v); } }