/// <summary>
        /// Calcule une prédiction pour deux facteurs
        /// </summary>
        /// <param name="pointFactorValue">Facteur lié aux layers de performance</param>
        /// <param name="serieFactorValue">Facteur lié aux séries de layers de performance</param>
        /// <returns></returns>
        public double predict(double pointFactorValue, double serieFactorValue)
        {
            PerfSerie ps          = new PerfSerie();
            double    output      = double.NaN;
            double    serieOutput = double.NaN;

            try {
                if (this.count == 1)
                {
                    // Il n'y a qu'une série dans la layer, donc serieFactorValue n'est pas utile
                    output = SerieAt(0).predict(pointFactorValue);
                }
                else
                {
                    // Si le domaine de calcul n'a pas été défini au préalable, il est réduit à l'étendue
                    // de la layer
                    if (!ranged)
                    {
                        setRange();
                    }
                    // Test du domaine de calcul
                    if (!isInRange(serieFactorValue))
                    {
                        throw new ModelException(AeroCalc.E_SERIE_VALUE_OUT_OF_RANGE,
                                                 this.outputName, "", serieFactorValue);
                    }
                    // Sélection des séries
                    selectSubLayer(serieFactorValue, 3);
                    // Calcul de la prédiction pour chaque série sélectionnée
                    for (int count = 0; count < this.count; count++)
                    {
                        if (SerieAt(count).selected)
                        {
                            serieOutput = SerieAt(count).predict(pointFactorValue);
                            ps.add(new PerfPoint(SerieAt(count).factorValue, serieOutput, false));
                        }
                    }
                    if (ps.count >= 1)
                    {
                        output = ps.predict(serieFactorValue);
                    }
                }
            } catch (ModelException e) {
                throw e;
            }
            return(output);
        }
        /// <summary>
        /// Calcule une prédiction tridimensionnelle
        /// </summary>
        /// <param name="pointFactorValue">Facteur des Point de performances</param>
        /// <param name="serieFactorValue">Facteur des Serie de performances</param>
        /// <param name="layerFactorValue">Facteur des Layer de performances</param>
        /// <returns>Double, valeur prédite pour les facteurs passés en arguments</returns>
        /// <remarks>
        /// TODO Cette fonction doit générer les différentes exceptions qui caractérisent les cas de calculs
        /// impossibles, mais ce n'est pas à la Pile d'intervenir dans le traitement des exceptions
        /// y compris pour stocker les informations liées à ces exceptions.
        /// Il reste à revoir la structure des blocs try, une imbrication n'est pas judicieuse
        /// Le bloc try primaire est visiblement trop étendu
        /// </remarks>
        public double predict(double pointFactorValue, double serieFactorValue, double layerFactorValue)
        {
            // Serie locale permettant une interpolation polynomiale sur 3 Layer en proximité avec layerFactorValue
            PerfSerie ps          = new PerfSerie();
            double    output      = double.NaN;
            double    layerOutput = double.NaN;

            try {
                if (this.count == 1)
                {
                    // Une seule layer, donc layerFactorValue est inutile
                    output = layerAt(0).predict(pointFactorValue, serieFactorValue);
                }
                else
                {
                    // Plusieurs Layer à traiter
                    // Définition du domaine de calcul, si non défini au préalable
                    if (!ranged)
                    {
                        setRange();
                    }
                    // Test du domaine de calcul
                    if (!isInRange(layerFactorValue))
                    {
                        throw new ModelException(AeroCalc.E_LAYER_VALUE_OUT_OF_RANGE,
                                                 this.outputName, this.layerFactorName, layerFactorValue);
                    }
                    // Sélection des layers
                    selectLayers(layerFactorValue, 3);
                    // Calcul de la prédiction pour chaque layer sélectionnée
                    for (int count = 0; count < this.count; count++)
                    {
                        if (layerAt(count).selected)
                        {
                            layerOutput = layerAt(count).predict(pointFactorValue, serieFactorValue);
                            // Abonde la Serie locale
                            ps.add(new PerfPoint(layerAt(count).factorValue, layerOutput, false));
                        }
                    }
                    if (ps.count >= 1)
                    {
                        //
                        // TODO, Attention, la fonction predict va travailler sur une création de données
                        // nécessaires à une interpolation sur plusieurs Layer. En cas d'exception, ce ne sont pas
                        // des données originales des modèles de performances.
                        // REVOIR l'imbrication des blocs try pour simplifier la structure du code
                        //
                        try {
                            output = ps.predict(layerFactorValue);
                        } catch (ModelException ee) {
                            ee.setFactor(layerFactorName, layerFactorValue);
                        }
                    }
                    else
                    {
                        throw new ModelException(AeroCalc.E_VOID_SYSTEM,
                                                 this.outputName, this.layerFactorName, layerFactorValue);
                    }
                }
            }
            catch (ModelException e) {
                output = double.NaN;
                if (e.modelName.Equals(""))
                {
                    e.setModelName(this.outputName);
                }
                switch (e.nature)
                {
                case AeroCalc.E_POINT_VALUE_OUT_OF_RANGE: e.setFactor(pointFactorName, pointFactorValue);
                    break;

                case AeroCalc.E_SERIE_VALUE_OUT_OF_RANGE: e.setFactor(serieFactorName, serieFactorValue);
                    break;

                case AeroCalc.E_LAYER_VALUE_OUT_OF_RANGE: e.setFactor(layerFactorName, layerFactorValue);
                    break;
                }
                throw;
            }
            return(output);
        }