Exemplo n.º 1
0
        public static double[] SolveInverse(
            IForwardSolver forwardSolver,
            IOptimizer optimizer,
            SolutionDomainType solutionDomainType,
            double[] dependentValues,
            double[] standardDeviationValues,
            InverseFitType inverseFitType,
            object[] independentValues,
            double[] lowerBounds,
            double[] upperBounds)
        {
            //var opticalPropertyGuess = ((OpticalProperties[]) (independentValues[0])).First();
            //var fitParameters = new double[4] { opticalPropertyGuess.Mua, opticalPropertyGuess.Musp, opticalPropertyGuess.G, opticalPropertyGuess.N };
            var parametersToFit = GetParametersToFit(inverseFitType);

            var opticalPropertyGuess = (OpticalProperties[])(independentValues[0]);
            var fitParametersArray   = opticalPropertyGuess.SelectMany(opgi => new[] { opgi.Mua, opgi.Musp, opgi.G, opgi.N }).ToArray();
            var parametersToFitArray = Enumerable.Range(0, opticalPropertyGuess.Count()).SelectMany(_ => parametersToFit).ToArray();

            Func <double[], object[], double[]> func = GetForwardReflectanceFuncForOptimization(forwardSolver, solutionDomainType);

            var fit = optimizer.SolveWithConstraints(fitParametersArray, parametersToFitArray, lowerBounds, upperBounds, dependentValues.ToArray(),
                                                     standardDeviationValues.ToArray(), func, independentValues.ToArray());

            return(fit);
        }
Exemplo n.º 2
0
        public static Complex[] ComputeFluenceComplex(
            IForwardSolver forwardSolver,
            FluenceSolutionDomainType solutionDomainType,
            // keeping us from uniting the above. needs to be a single SolutionDomainType enum
            IndependentVariableAxis[] independentAxesTypes,
            double[][] independentValues,
            OpticalProperties opticalProperties,
            params double[] constantValues)
        {
            var parameters = new double[4]
            {
                opticalProperties.Mua, opticalProperties.Musp, opticalProperties.G,
                opticalProperties.N
            };

            // todo: current assumption below is that the second axes is z. need to generalize
            var func = GetForwardFluenceFuncComplex(forwardSolver, solutionDomainType, independentAxesTypes[0]);

            // create a list of inputs (besides optical properties) that corresponds to the behavior of the function above
            List <object> inputValues = new List <object>(independentValues);

            constantValues.ForEach(cv => inputValues.Add(cv));

            return(func(parameters, inputValues.ToArray()));
        }
        // Steady-State Domain...
        ///// <summary>
        ///// Steady-State centerline Photon Hitting Density by the Green's function multiplication
        ///// </summary>
        ///// <param name="ops">optical properties object</param>
        ///// <param name="rhos">Source Detector separation</param>
        ///// <param name="rProbe">Radial distance from source to "iterogation" location</param>
        ///// <param name="z">Depth being probed</param>
        ///// <returns>The Photon Hitting Density at specified location</returns>
        //public IEnumerable<double> SteadyStatePointSourceCenterlinePHD(IEnumerable<OpticalProperties> ops, IEnumerable<double> rProbes,
        //     IEnumerable<double> rhos, IEnumerable<double> zs)
        //{
        //    foreach (var op in ops)
        //    {
        //        DiffusionParameters dp = DiffusionParameters.Create(op, ForwardModel.SDA);
        //        foreach (var rProbe in rProbes)
        //        {
        //            foreach (var rho in rhos)
        //            {
        //                foreach (var z in zs)
        //                {
        //                    var r11 = DiffusionBase.Radius1(rProbe, z, dp.zp);
        //                    var r12 = DiffusionBase.Radius2(rProbe, z, dp.zp, dp.zb);
        //                    var r21 = DiffusionBase.Radius1(rho - rProbe, z, 0.0);
        //                    var r22 = DiffusionBase.Radius2(rho - rProbe, z, 0.0, dp.zb);
        //                    var fluence1 = DiffusionBase.SteadyStatePointSourceImageGreensFunction(dp, r11, r12);
        //                    var fluence2 = DiffusionBase.SteadyStatePointSourceImageGreensFunction(dp, r21, r22);
        //                    yield return (fluence1 * fluence2);
        //                }
        //            }
        //        }
        //    }
        //}


        public static IEnumerable <Complex> TimeFrequencyDomainFluence2SurfacePointPHD(
            this IForwardSolver myForwardSolver,
            double timeModulationFrequency,
            IEnumerable <OpticalProperties> ops,
            IEnumerable <double> rhoPrimes, IEnumerable <double> zs)
        {
            foreach (var op in ops)
            {
                DiffusionParameters dp = DiffusionParameters.Create(op, ForwardModel.SDA);
                Complex             k  =
                    (
                        (op.Mua * dp.cn + Complex.ImaginaryOne * timeModulationFrequency * 2 * Math.PI) /
                        (dp.D * dp.cn)
                    ).SquareRoot();
                foreach (var rho in rhoPrimes)
                {
                    foreach (var z in zs)
                    {
                        var r21 = CalculatorToolbox.GetRadius(rho, z);
                        var r22 = CalculatorToolbox.GetRadius(rho, z + 2 * dp.zb);
                        yield return
                            (DiffusionGreensFunctions.TemporalFrequencyPointSourceImageGreensFunction(dp, r21, r22, k));
                    }
                }
            }
        }
Exemplo n.º 4
0
        private static Func <double[], object[], double[]> GetForwardReflectanceFuncForOptimization(
            IForwardSolver fs, SolutionDomainType type)
        {
            Func <object[], double[]> forwardReflectanceFunc = GetForwardReflectanceFunc(fs, type);

            return((fitData, allParameters) =>
            {
                // place optical property array in the first position, and the rest following
                var forwardData = ((object)UnFlattenOpticalProperties(fitData)).AsEnumerable().Concat(allParameters.Skip(1)).ToArray();
                return forwardReflectanceFunc(forwardData);
            });
        }
Exemplo n.º 5
0
        private static Func <object[], double[]> GetForwardReflectanceFunc(IForwardSolver fs, SolutionDomainType type)
        {
            switch (type)
            {
            case SolutionDomainType.ROfRho:
                if (fs is TwoLayerSDAForwardSolver)     // todo: future generalization to IMultiRegionForwardSolver?
                {
                    return(forwardData => fs.ROfRho((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1]));
                }
                return(forwardData => fs.ROfRho(ops: (OpticalProperties[])forwardData[0], rhos: (double[])forwardData[1]));

            case SolutionDomainType.ROfFx:
                if (fs is TwoLayerSDAForwardSolver)
                {
                    return(forwardData => fs.ROfFx((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1]));
                }
                return(forwardData => fs.ROfFx(ops: (OpticalProperties[])forwardData[0], fxs: (double[])forwardData[1]));

            case SolutionDomainType.ROfRhoAndTime:
                if (fs is TwoLayerSDAForwardSolver)
                {
                    return(forwardData => fs.ROfRhoAndTime((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1], (double[])forwardData[2]));
                }
                return(forwardData => fs.ROfRhoAndTime(ops: (OpticalProperties[])forwardData[0], rhos: (double[])forwardData[1], ts: (double[])forwardData[2]));

            case SolutionDomainType.ROfFxAndTime:
                if (fs is TwoLayerSDAForwardSolver)
                {
                    return(forwardData => fs.ROfFxAndTime((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1], (double[])forwardData[2]));
                }
                return(forwardData => fs.ROfFxAndTime(ops: (OpticalProperties[])forwardData[0], fxs: (double[])forwardData[1], ts: (double[])forwardData[2]));

            case SolutionDomainType.ROfRhoAndFt:
                if (fs is TwoLayerSDAForwardSolver)
                {
                    return(forwardData => fs.ROfRhoAndFt((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1], (double[])forwardData[2]).FlattenRealAndImaginary());
                }
                return(forwardData => fs.ROfRhoAndFt(ops: (OpticalProperties[])forwardData[0], rhos: (double[])forwardData[1], fts: (double[])forwardData[2]).FlattenRealAndImaginary());

            case SolutionDomainType.ROfFxAndFt:
                if (fs is TwoLayerSDAForwardSolver)
                {
                    return(forwardData => fs.ROfFxAndFt((IOpticalPropertyRegion[][])forwardData[0], (double[])forwardData[1], (double[])forwardData[2]).FlattenRealAndImaginary());
                }
                return(forwardData => fs.ROfFxAndFt(ops: (OpticalProperties[])forwardData[0], fxs: (double[])forwardData[1], fts: (double[])forwardData[2]).FlattenRealAndImaginary());

            default:
                throw new ArgumentOutOfRangeException("type");
            }
        }
Exemplo n.º 6
0
        // overload for ITissueRegion forward solvers todo: merge with above?
        public static double[] ComputeFluence(
            IForwardSolver forwardSolver,
            FluenceSolutionDomainType solutionDomainType,
            // keeping us from uniting the above. needs to be a single SolutionDomainType enum
            IndependentVariableAxis[] independentAxesTypes,
            double[][] independentValues,
            IOpticalPropertyRegion[] tissueRegions,
            params double[] constantValues)
        {
            var parameters = tissueRegions.SelectMany(region =>
            {
                double[] regionParameters = null;
                if (region is ILayerOpticalPropertyRegion)
                {
                    var layerRegion  = (ILayerOpticalPropertyRegion)region;
                    regionParameters = new[]
                    {
                        layerRegion.RegionOP.Mua,
                        layerRegion.RegionOP.Musp,
                        layerRegion.RegionOP.G,
                        layerRegion.RegionOP.N,
                        layerRegion.ZRange.Delta
                    };
                }
                //else if(region is EllipsoidTissueRegion)
                //{
                //
                //}
                else
                {
                    throw new Exception("Forward model " +
                                        forwardSolver.ToString() +
                                        " is not supported.");
                }
                return(regionParameters);
            }).ToArray();

            // todo: current assumption below is that the second axis is z. need to generalize
            var func = GetForwardFluenceFunc(forwardSolver, solutionDomainType, independentAxesTypes[0]);

            // create a list of inputs (besides optical properties) that corresponds to the behavior of the function above
            List <object> inputValues = new List <object>(independentValues);

            constantValues.ForEach(cv => inputValues.Add(cv));

            return(func(parameters, inputValues.ToArray()));
        }
Exemplo n.º 7
0
        private static Func <double[], object[], Complex[]> GetForwardFluenceFuncComplex(
            IForwardSolver fs, FluenceSolutionDomainType type, IndependentVariableAxis axis)
        {
            Func <double[], OpticalProperties> getOP = op => new OpticalProperties(op[0], op[1], op[2], op[3]);

            // note: the following uses the convention that the independent variable(s) is (are) first in the forward data object array
            // note: secondly, if there are multiple independent axes, they will be assigned in order of appearance in the method signature
            switch (type)
            {
            case FluenceSolutionDomainType.FluenceOfRhoAndZAndFt:
                switch (axis)
                {
                case IndependentVariableAxis.Rho:
                    if (fs is TwoLayerSDAForwardSolver)         // todo: future generalization to IMultiRegionForwardSolver?
                    {
                        return((fitData, otherData) => fs.FluenceOfRhoAndZAndFt(new[] { getLayerTissueRegionArray(fitData) }, (double[])otherData[0], (double[])otherData[1], new[] { (double)otherData[2] }));
                    }
                    return((fitData, otherData) => fs.FluenceOfRhoAndZAndFt(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1], new[] { (double)otherData[2] }));

                case IndependentVariableAxis.Ft:
                    if (fs is TwoLayerSDAForwardSolver)
                    {
                        return((fitData, otherData) => fs.FluenceOfRhoAndZAndFt(new[] { getLayerTissueRegionArray(fitData) }, (double[])otherData[2], (double[])otherData[1], new[] { (double)otherData[0] }));
                    }
                    return((fitData, otherData) => fs.FluenceOfRhoAndZAndFt(new[] { getOP(fitData) }, new[] { (double)otherData[2] }, (double[])otherData[1], (double[])otherData[0]));

                default:
                    throw new ArgumentOutOfRangeException("axis");
                }

            case FluenceSolutionDomainType.FluenceOfFxAndZAndFt:
                switch (axis)
                {
                case IndependentVariableAxis.Fx:
                    return((fitData, otherData) => fs.FluenceOfFxAndZAndFt(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1], new[] { (double)otherData[2] }));

                case IndependentVariableAxis.Ft:
                    return((fitData, otherData) => fs.FluenceOfFxAndZAndFt(new[] { getOP(fitData) }, new[] { (double)otherData[2] }, (double[])otherData[1], (double[])otherData[0]));

                default:
                    throw new ArgumentOutOfRangeException("axis");
                }

            default:
                throw new ArgumentOutOfRangeException("type");
            }
        }
Exemplo n.º 8
0
 // overload that calls the above method with just one set of optical properties
 public static double[] ComputeFluence(
     IForwardSolver forwardSolver,
     FluenceSolutionDomainType solutionDomainType,
     // keeping us from uniting the above. needs to be a single SolutionDomainType enum
     IndependentVariableAxis[] independentAxesTypes,
     double[][] independentValues,
     OpticalProperties opticalProperties,
     params double[] constantValues)
 {
     return(ComputeFluence(
                forwardSolver,
                solutionDomainType,
                independentAxesTypes,
                independentValues,
                new[] { opticalProperties },
                constantValues));
 }
Exemplo n.º 9
0
        public static double[] ComputeReflectance(
            IForwardSolver forwardSolver,
            SolutionDomainType solutionDomainType,
            ForwardAnalysisType forwardAnalysisType,
            object[] independentValues)
        {
            Func <object[], double[]> func = GetForwardReflectanceFunc(forwardSolver, solutionDomainType);

            //Func<SolutionDomainType, ForwardAnalysisType, IndependentVariableAxis[], double[]> getOptimizationParameters = (_,_,_) =>
            //    new[] { op.Mua, op.Musp, op.G, op.N }
            //double[] optimizationParameters = GetOptimizationParameters(forwardSolver, solutionDomainType, independentAxisTypes); // will need this for inverse solver

            // create a list of inputs (besides optical properties) that corresponds to the behavior of the function above

            return(forwardAnalysisType == ForwardAnalysisType.R
                ? func(independentValues)
                : func.GetDerivativeFunc(forwardAnalysisType)(independentValues));
        }
Exemplo n.º 10
0
        /// <summary>
        /// Method to generate PHD
        /// </summary>
        /// <param name="forwardSolver">forward solver</param>
        /// <param name="fluence">fluence</param>
        /// <param name="sdSeparation">source detector separation (in mm)</param>
        /// <param name="ops">optical properties</param>
        /// <param name="rhos">detector locations (in mm)</param>
        /// <param name="zs">z values (in mm)</param>
        /// <returns></returns>
        public static double[] GetPHD(IForwardSolver forwardSolver, double[] fluence, double sdSeparation,
                                      OpticalProperties[] ops, double[] rhos, double[] zs)
        {
            var rhoPrimes =
                from r in rhos
                select r - sdSeparation;

            var greensFunction = forwardSolver.SteadyStateFluence2SurfacePointPHD(ops, rhoPrimes, zs);

            var phd = new double[fluence.Length];

            phd.PopulateFromEnumerable(Enumerable.Zip(fluence, greensFunction, (flu, green) => flu * green));

            return(phd);

            // replaced with pre-initialized array + "PopulateFromEnumerable" call instead of growing array dynamically
            //System.Linq.Enumerable.Zip(fluence, greensFunction, (flu, green) => flu * green).ToArray();
        }
 public static IEnumerable <double> SteadyStateFluence2SurfacePointPHD(
     this IForwardSolver myForwardSolver,
     IEnumerable <OpticalProperties> ops,
     IEnumerable <double> rhoPrimes, IEnumerable <double> zs)
 {
     foreach (var op in ops)
     {
         DiffusionParameters dp = DiffusionParameters.Create(op, ForwardModel.SDA);
         foreach (var rho in rhoPrimes)
         {
             foreach (var z in zs)
             {
                 var r21 = CalculatorToolbox.GetRadius(rho, z);
                 var r22 = CalculatorToolbox.GetRadius(rho, z + 2 * dp.zb);
                 yield return
                     (DiffusionGreensFunctions.StationaryPointSourceImageGreensFunction(dp, r21, r22));
             }
         }
     }
 }
Exemplo n.º 12
0
        public static double[] ComputeFluence(
            IForwardSolver forwardSolver,
            FluenceSolutionDomainType solutionDomainType, // keeping us from uniting the above. needs to be a single SolutionDomainType enum
            IndependentVariableAxis[] independentAxesTypes,
            double[][] independentValues,
            OpticalProperties[] opticalProperties,
            params double[] constantValues)
        {
            // todo: current assumption below is that the second axes is z. need to generalize
            var func = GetForwardFluenceFunc(forwardSolver, solutionDomainType, independentAxesTypes[0]);

            // create a list of inputs (besides optical properties) that corresponds to the behavior of the function above
            List <object> inputValues = new List <object>(independentValues);

            constantValues.ForEach(cv => inputValues.Add(cv));

            if (opticalProperties.Length == 1) // optimization that skips duplicate arrays if we're not multiplexing over optical properties (e.g. wavelength)
            {
                var op         = opticalProperties[0];
                var parameters = new[] { op.Mua, op.Musp, op.G, op.N };
                return(func(parameters, inputValues.ToArray()));
            }

            var numOp   = opticalProperties.Length;
            var numIv   = independentValues.Length;
            var fluence = new double[numOp * numIv];

            for (int opi = 0; opi < numOp; opi++) // todo: parallelize
            {
                var op         = opticalProperties[opi];
                var parameters = new[] { op.Mua, op.Musp, op.G, op.N };
                var tempValues = func(parameters, inputValues.ToArray());

                for (int ivi = 0; ivi < numIv; ivi++)
                {
                    fluence[opi * numIv + ivi] = tempValues[ivi];
                }
            }
            return(fluence);
        }
        public static IEnumerable <double> TemporalPointSourceCenterlinePHD(
            this IForwardSolver myForwardSolver,
            IEnumerable <OpticalProperties> ops, IEnumerable <double> rProbes,
            IEnumerable <double> rhos, IEnumerable <double> zs, IEnumerable <double> ts)
        {
            foreach (var op in ops)
            {
                DiffusionParameters dp = DiffusionParameters.Create(op, ForwardModel.SDA);
                foreach (var rProbe in rProbes)
                {
                    foreach (var rho in rhos)
                    {
                        foreach (var z in zs)
                        {
                            var r11 = CalculatorToolbox.GetRadius(rProbe, z - dp.zp);
                            var r12 = CalculatorToolbox.GetRadius(rProbe, z + dp.zp + 2 * dp.zb);
                            var r21 = CalculatorToolbox.GetRadius(rho - rProbe, z);
                            var r22 = CalculatorToolbox.GetRadius(rho - rProbe, z + 2 * dp.zb);

                            foreach (var t in ts)
                            {
                                Func <double, double> integrandConvolve =
                                    tau =>
                                {
                                    return
                                        (DiffusionGreensFunctions.TemporalPointSourceImageGreensFunction
                                             (dp, r11, r12, tau) *
                                         DiffusionGreensFunctions.TemporalPointSourceImageGreensFunction
                                             (dp, r21, r22, t - tau));
                                };
                                yield return(FunctionMath.Integrate(
                                                 integrandConvolve, Meta.Numerics.Interval.FromEndpoints(0.0, t)));
                            }
                        }
                    }
                }
            }
        }
        ///// <summary>
        ///// Modified from a code of Fred's written in Matlab
        ///// </summary>
        ///// <param name="dp">diffusion parameters object</param>
        ///// <param name="k">complex diffusion constant, ((mua*cn +i*(ft*2*pi))/(D*cn)).^0.5</param>
        ///// <param name="rho">source-detector separation</param>
        ///// <param name="rProbe">radius from source</param>
        ///// <param name="y">omitted</param>
        ///// <param name="z">depth</param>
        ///// <param name="ft">temporal frequency</param>
        ///// <returns></returns>
        //public static double DepthProbFrequencyDomainPhotonMigration(DiffusionParameters dp, Complex k,
        //    double rho, double rProbe, double z, double ft)
        //{
        //    var r11 = DiffusionBase.Radius1(rho, z, dp.zp);
        //    var r12 = DiffusionBase.Radius2(rho, z, dp.zp, dp.zb);
        //    var r21 = DiffusionBase.Radius1(rProbe - rho, z, 0.0);
        //    var r22 = DiffusionBase.Radius2(rProbe - rho, z, 0.0, dp.zb);
        //    var phi1 = SDAForwardSolver.TemporalFrequencyFluence(dp, k, r11, r12);
        //    var phi2 = SDAForwardSolver.TemporalFrequencyFluence(dp, k, r21, r22);
        //    return (phi1 * phi2).Modulus; // see Kienle and Patterson, JOSA A 14(1), 246-254,1997
        //}

        public static IEnumerable <double> TemporalFrequencyPointSourceCenterlinePHD(
            this IForwardSolver myForwardSolver, IEnumerable <OpticalProperties> ops,
            IEnumerable <double> rProbes, IEnumerable <double> rhos,
            IEnumerable <double> zs, IEnumerable <double> fts)
        {
            foreach (var op in ops)
            {
                DiffusionParameters dp = DiffusionParameters.Create(op, ForwardModel.SDA);
                foreach (var rProbe in rProbes)
                {
                    foreach (var rho in rhos)
                    {
                        foreach (var z in zs)
                        {
                            var r11 = CalculatorToolbox.GetRadius(rProbe, z - dp.zp);
                            var r12 = CalculatorToolbox.GetRadius(rProbe, z + dp.zp + 2 * dp.zb);
                            var r21 = CalculatorToolbox.GetRadius(rho - rProbe, z);
                            var r22 = CalculatorToolbox.GetRadius(rho - rProbe, z + 2 * dp.zb);

                            foreach (var ft in fts)
                            {
                                Complex k =
                                    (
                                        (op.Mua * dp.cn + Complex.ImaginaryOne * ft * 2 * Math.PI) /
                                        (dp.D * dp.cn)
                                    ).SquareRoot();
                                var phi1 = DiffusionGreensFunctions.TemporalFrequencyPointSourceImageGreensFunction(
                                    dp, r11, r12, k);
                                var phi2 = DiffusionGreensFunctions.TemporalFrequencyPointSourceImageGreensFunction(
                                    dp, r21, r22, k);

                                yield return((phi1 * phi2).Magnitude);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 15
0
        // todo: array overloads for fluence forward solvers too
        private static Func <double[], object[], double[]> GetForwardFluenceFunc(
            IForwardSolver fs, FluenceSolutionDomainType type, IndependentVariableAxis axis)
        {
            Func <double[], OpticalProperties> getOP = op => new OpticalProperties(op[0], op[1], op[2], op[3]);

            // note: the following uses the convention that the independent variable(s) is (are) first in the forward data object array
            // note: secondly, if there are multiple independent axes, they will be assigned in order of appearance in the method signature
            switch (type)
            {
            case FluenceSolutionDomainType.FluenceOfRhoAndZ:
                if (fs is TwoLayerSDAForwardSolver)     // todo: future generalization to IMultiRegionForwardSolver?
                {
                    return((fitData, otherData) => fs.FluenceOfRhoAndZ(new[] { getLayerTissueRegionArray(fitData) }, (double[])otherData[0], (double[])otherData[1]));
                }
                return((fitData, otherData) => fs.FluenceOfRhoAndZ(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1]));

            case FluenceSolutionDomainType.FluenceOfFxAndZ:
                return((fitData, otherData) => fs.FluenceOfFxAndZ(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1]));

            case FluenceSolutionDomainType.FluenceOfRhoAndZAndTime:
                switch (axis)
                {
                case IndependentVariableAxis.Rho:
                    return((fitData, otherData) => fs.FluenceOfRhoAndZAndTime(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1], new[] { (double)otherData[2] }));

                case IndependentVariableAxis.Time:
                    return((fitData, otherData) => fs.FluenceOfRhoAndZAndTime(new[] { getOP(fitData) }, new[] { (double)otherData[2] }, (double[])otherData[1], (double[])otherData[0]));

                //case IndependentVariableAxis.Wavelength:
                //    return (chromPlusMusp, constantData) =>
                //               {
                //                   var wv = (double[]) constantData[0];
                //                   var tissue = (Tissue) constantData[1];
                //                   int i = 0;
                //                   tissue.Absorbers.ForEach(abs => abs.Concentration = chromPlusMusp[i++]);
                //                   tissue.Scatterer = new PowerLawScatterer(chromPlusMusp[i], chromPlusMusp[i + 1]);
                //                   var muas = wv.Select(w => tissue.GetMua(w));
                //                   var musps = wv.Select(w => tissue.GetMusp(w));
                //                   return EnumerableExtensions.Zip(muas,musps,(mua,musp)=>fs.ROfRhoAndTime())...
                //               };
                //    return op => fs.ROfRhoAndTime(op, ((double)constantValues[0]).AsEnumerable(), ((double)constantValues[1]).AsEnumerable());
                default:
                    throw new ArgumentOutOfRangeException("axis");
                }

            case FluenceSolutionDomainType.FluenceOfFxAndZAndTime:
                switch (axis)
                {
                case IndependentVariableAxis.Fx:
                    return((fitData, otherData) => fs.FluenceOfFxAndZAndTime(new[] { getOP(fitData) }, (double[])otherData[0], (double[])otherData[1], new[] { (double)otherData[2] }));

                case IndependentVariableAxis.Time:
                    return((fitData, otherData) => fs.FluenceOfFxAndZAndTime(new[] { getOP(fitData) }, new[] { (double)otherData[2] }, (double[])otherData[1], (double[])otherData[0]));

                default:
                    throw new ArgumentOutOfRangeException("axis");
                }

            default:
                throw new ArgumentOutOfRangeException("type");
            }
        }
 public VectorizedForwardSolverFuncs(IForwardSolver fs)
 {
     _fs = fs;
 }