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())); }
// 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())); }
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"); } }
// 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)); }
public static double[] ComputeFluence( ForwardSolverType forwardSolverType, FluenceSolutionDomainType solutionDomainType, // keeping us from uniting the above. needs to be a single SolutionDomainType enum IndependentVariableAxis[] independentAxesTypes, double[][] independentValues, OpticalProperties[] opticalProperties, params double[] constantValues) { // use factory method on each call, as opposed to injecting an instance from the outside // -- still time-efficient if singletons are used // -- potentially memory-inefficient if the user creates lots of large solver instances return(ComputeFluence( SolverFactory.GetForwardSolver(forwardSolverType), solutionDomainType, independentAxesTypes, independentValues, opticalProperties, constantValues)); }
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 string GetUnits(this FluenceSolutionDomainType sdType) { switch (sdType) { case FluenceSolutionDomainType.FluenceOfRhoAndZ: default: return(DependentVariableAxisUnits.PerMMCubed.GetInternationalizedString()); case FluenceSolutionDomainType.FluenceOfFxAndZ: return(DependentVariableAxisUnits.PerMM.GetInternationalizedString()); case FluenceSolutionDomainType.FluenceOfRhoAndZAndTime: return(DependentVariableAxisUnits.PerMMCubedPerNS.GetInternationalizedString()); case FluenceSolutionDomainType.FluenceOfFxAndZAndTime: return(DependentVariableAxisUnits.PerMMPerNS.GetInternationalizedString()); case FluenceSolutionDomainType.FluenceOfRhoAndZAndFt: return(DependentVariableAxisUnits.PerMMCubedPerGHz.GetInternationalizedString()); case FluenceSolutionDomainType.FluenceOfFxAndZAndFt: return(DependentVariableAxisUnits.PerMMPerGHz.GetInternationalizedString()); } }
// 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 static bool IsComplexSolver(FluenceSolutionDomainType solutionDomainType) { return ((solutionDomainType == FluenceSolutionDomainType.FluenceOfRhoAndZAndFt) || (solutionDomainType == FluenceSolutionDomainType.FluenceOfFxAndZAndFt)); }
public static bool IsSolverWithConstantValues(FluenceSolutionDomainType solutionDomainType) { return (!(solutionDomainType == FluenceSolutionDomainType.FluenceOfRhoAndZ) && !(solutionDomainType == FluenceSolutionDomainType.FluenceOfFxAndZ)); }