示例#1
0
        public PlotViewModel(int plotViewId = 0)
        {
            _plotViewId = plotViewId;
            _MinYValue  = 1E-9;
            _MaxYValue  = 1.0;
            _MinXValue  = 1E-9;
            _MaxXValue  = 1.0;
            _AutoScaleX = true;
            _AutoScaleY = true;

            RealLabels           = new List <string>();
            ImagLabels           = new List <string>();
            PhaseLabels          = new List <string>();
            AmplitudeLabels      = new List <string>();;
            Labels               = new List <string>();
            PlotTitles           = new List <string>();
            DataSeriesCollection = new List <DataPointCollection>();
            PlotSeriesCollection = new PlotPointCollection();
            //IsComplexPlot = false;

            PlotModel = new PlotModel
            {
                Title           = "",
                LegendPlacement = LegendPlacement.Outside
            };
            PlotType               = ReflectancePlotType.ForwardSolver;
            _HoldOn                = true;
            _HideKey               = false;
            _ShowInPlotView        = true;
            _ShowAxes              = false;
            _showComplexPlotToggle = false;

            XAxisSpacingOptionVM = new OptionViewModel <ScalingType>("XAxisSpacing_" + _plotViewId, false);
            XAxisSpacingOptionVM.PropertyChanged += (sender, args) => UpdatePlotSeries();

            YAxisSpacingOptionVM = new OptionViewModel <ScalingType>("YAxisSpacing_" + _plotViewId, false);
            YAxisSpacingOptionVM.PropertyChanged += (sender, args) => UpdatePlotSeries();

            PlotToggleTypeOptionVM = new OptionViewModel <PlotToggleType>("ToggleType_" + _plotViewId, false);
            PlotToggleTypeOptionVM.PropertyChanged += (sender, args) => UpdatePlotSeries();

            PlotNormalizationTypeOptionVM = new OptionViewModel <PlotNormalizationType>("NormalizationType_" + _plotViewId, false);
            PlotNormalizationTypeOptionVM.PropertyChanged += (sender, args) => UpdatePlotSeries();

            CustomPlotLabel = "";

            Commands.Plot_PlotValues.Executed    += Plot_Executed;
            Commands.Plot_SetAxesLabels.Executed += Plot_SetAxesLabels_Executed;

            ClearPlotCommand        = new RelayCommand(() => Plot_Cleared(null, null));
            ClearPlotSingleCommand  = new RelayCommand(() => Plot_ClearedSingle(null, null));
            ExportDataToTextCommand = new RelayCommand(() => Plot_ExportDataToText_Executed(null, null));
            DuplicateWindowCommand  = new RelayCommand(() => Plot_DuplicateWindow_Executed(null, null));
        }
示例#2
0
        private void UpdateOptions()
        {
            switch (SelectedValue)
            {
            case FluenceSolutionDomainType.FluenceOfRhoAndZ:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Rho });
                FluenceOfRhoAndZOption.IsSelected = true;     //added to force the radio button when it is changed programatically
                break;

            case FluenceSolutionDomainType.FluenceOfFxAndZ:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Fx });
                break;

            case FluenceSolutionDomainType.FluenceOfRhoAndZAndTime:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Rho, IndependentVariableAxis.Time });
                break;

            case FluenceSolutionDomainType.FluenceOfFxAndZAndTime:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Fx, IndependentVariableAxis.Time });
                break;

            case FluenceSolutionDomainType.FluenceOfRhoAndZAndFt:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Rho, IndependentVariableAxis.Ft });
                break;

            case FluenceSolutionDomainType.FluenceOfFxAndZAndFt:
                IndependentVariableAxisOptionVM =
                    new OptionViewModel <IndependentVariableAxis>("IndependentAxis", false,
                                                                  new[] { IndependentVariableAxis.Fx, IndependentVariableAxis.Ft });
                break;

            default:
                throw new NotImplementedException("SelectedValue");
            }

            // create a new callback based on the new viewmodel
            IndependentVariableAxisOptionVM.PropertyChanged += (s, a) => UpdateAxes();

            UpdateAxes();
            //The independent axis should not be visible, this panel already has modulation frequency
            ShowIndependentAxisChoice = (ShowIndependentAxisChoice && ((SelectedValue != FluenceSolutionDomainType.FluenceOfRhoAndZAndFt) && (SelectedValue != FluenceSolutionDomainType.FluenceOfRhoAndZAndTime)));
        }
示例#3
0
        public SimulationOptionsViewModel(SimulationOptions options)
        {
            _simulationOptions = options; // use the property to invoke the appropriate change notification

#if WHITELIST
            _absorptionWeightingTypeVM   = new OptionViewModel <AbsorptionWeightingType>("Absorption Weighting Type:", false, _simulationOptions.AbsorptionWeightingType, WhiteList.AbsorptionWeightingTypes);
            _randomNumberGeneratorTypeVM = new OptionViewModel <RandomNumberGeneratorType>("Random Number Generator Type:", false, _simulationOptions.RandomNumberGeneratorType, WhiteList.RandomNumberGeneratorTypes);
            _phaseFunctionTypeVM         = new OptionViewModel <PhaseFunctionType>("Phase Function Type:", false, _simulationOptions.PhaseFunctionType, WhiteList.PhaseFunctionTypes);
#else
            _absorptionWeightingTypeVM   = new OptionViewModel <AbsorptionWeightingType>("Absorption Weighting Type:", false, _simulationOptions.AbsorptionWeightingType);
            _randomNumberGeneratorTypeVM = new OptionViewModel <RandomNumberGeneratorType>("Random Number Generator:", false, _simulationOptions.RandomNumberGeneratorType);
            _phaseFunctionTypeVM         = new OptionViewModel <PhaseFunctionType>("Phase Function Type:", false, _simulationOptions.PhaseFunctionType);
#endif

            _absorptionWeightingTypeVM.PropertyChanged += (sender, args) =>
                                                          _simulationOptions.AbsorptionWeightingType = _absorptionWeightingTypeVM.SelectedValue;
            _randomNumberGeneratorTypeVM.PropertyChanged += (sender, args) =>
                                                            _simulationOptions.RandomNumberGeneratorType = _randomNumberGeneratorTypeVM.SelectedValue;
            _phaseFunctionTypeVM.PropertyChanged += (sender, args) =>
                                                    _simulationOptions.PhaseFunctionType = _phaseFunctionTypeVM.SelectedValue;
        }
        public MeshViewModel()
        {
            MinValue  = 1E-9;
            MaxValue  = 50.0;
            AutoScale = false;

            ScalingTypeOptionVM = new OptionViewModel <ScalingType>("Scaling Type:", false);
            ScalingTypeOptionVM.PropertyChanged += (sender, args) => UpdateImages();

            ColormapTypeOptionVM = new OptionViewModel <ColormapType>("Colormap Type:");
            _colormap            = new Colormap(ColormapTypeOptionVM.SelectedValue);
            ColormapTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                _colormap = new Colormap(ColormapTypeOptionVM.SelectedValue);
                UpdateImages();
            };

            ExportDataCommand = new RelayCommand(() => ExportData_Executed(null, null));

            Commands.Mesh_PlotMap.Executed += Mesh_PlotMap_Executed;
        }
        public SimulationInputViewModel(SimulationInput input)
        {
            _simulationInput = input; // use the property to invoke the appropriate change notification

            _simulationOptionsVM = new SimulationOptionsViewModel(_simulationInput.Options);

#if WHITELIST
            TissueTypeVM = new OptionViewModel <string>("Tissue Type:", true, _simulationInput.TissueInput.TissueType, WhiteList.TissueTypes);
#else
            TissueTypeVM = new OptionViewModel <string>("Tissue Type:", true, _simulationInput.TissueInput.TissueType,
                                                        new[]
            {
                "MultiLayer",
                "SingleEllipsoid",
            });
#endif

            _tissueTypeVM.PropertyChanged += (sender, args) =>
            {
                switch (_tissueTypeVM.SelectedValue)
                {
                case "MultiLayer":
                    _simulationInput.TissueInput = new MultiLayerTissueInput();
                    break;

                case "SingleEllipsoid":
                    _simulationInput.TissueInput = new SingleEllipsoidTissueInput();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                UpdateTissueTypeVM(_simulationInput.TissueInput.TissueType);
            };

            UpdateTissueInputVM(_simulationInput.TissueInput);
        }
        public MapViewModel(int MapViewId = 0)
        {
            _mapViewId = MapViewId;
            MinValue   = 1E-9;
            MaxValue   = 1.0;
            AutoScale  = false;

            ScalingTypeOptionVM = new OptionViewModel <ScalingType>(StringLookup.GetLocalizedString("Label_ScalingType") + _mapViewId, false);
            ScalingTypeOptionVM.PropertyChanged += (sender, args) => UpdateImages();

            ColormapTypeOptionVM = new OptionViewModel <ColormapType>(StringLookup.GetLocalizedString("Label_ColormapType"));
            ColormapTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                _colormap = new Colormap(ColormapTypeOptionVM.SelectedValue);
                UpdateImages();
            };

            _colormap = new Colormap(ColormapTypeOptionVM.SelectedValue);

            Commands.Maps_PlotMap.Executed += Maps_PlotMap_Executed;

            ExportDataToTextCommand = new RelayCommand(() => Maps_ExportDataToText_Executed(null, null));
            DuplicateWindowCommand  = new RelayCommand(() => Map_DuplicateWindow_Executed(null, null));
        }
示例#7
0
        public FluenceSolverViewModel()
        {
            RhoRangeVM = new RangeViewModel(new DoubleRange(0.1, 19.9, 300), "mm", IndependentVariableAxis.Rho, "");
            ZRangeVM   = new RangeViewModel(new DoubleRange(0.1, 19.9, 300), "mm", IndependentVariableAxis.Z, "");
            SourceDetectorSeparation = 10.0;
            TimeModulationFrequency  = 0.1;
            _tissueInputVM           = new OpticalPropertyViewModel();

            // right now, we're doing manual databinding to the selected item. need to enable databinding
            // confused, though - do we need to use strings? or, how to make generics work with dependency properties?
            ForwardSolverTypeOptionVM = new OptionViewModel <ForwardSolverType>(
                "Forward Model:",
                false,
                new[]
            {
                ForwardSolverType.DistributedPointSourceSDA,
                ForwardSolverType.PointSourceSDA,
                ForwardSolverType.DistributedGaussianSourceSDA,
                ForwardSolverType.TwoLayerSDA
            });     // explicitly enabling these for the workshop;

            FluenceSolutionDomainTypeOptionVM = new FluenceSolutionDomainOptionViewModel("Fluence Solution Domain", FluenceSolutionDomainType.FluenceOfRhoAndZ);
            FluenceSolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndTimeEnabled = false;
            FluenceSolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndFtEnabled   = true;
            AbsorbedEnergySolutionDomainTypeOptionVM = new FluenceSolutionDomainOptionViewModel("Absorbed Energy Solution Domain", FluenceSolutionDomainType.FluenceOfRhoAndZ);
            AbsorbedEnergySolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndTimeEnabled = false;
            AbsorbedEnergySolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndFtEnabled   = true;
            PhotonHittingDensitySolutionDomainTypeOptionVM = new FluenceSolutionDomainOptionViewModel("PHD Solution Domain", FluenceSolutionDomainType.FluenceOfRhoAndZ);
            PhotonHittingDensitySolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndTimeEnabled = false;
            PhotonHittingDensitySolutionDomainTypeOptionVM.IsFluenceOfRhoAndZAndFtEnabled   = true;
            PropertyChangedEventHandler updateSolutionDomain = (sender, args) =>
            {
                if (args.PropertyName == "IndependentAxisType")
                {
                    RhoRangeVM = ((FluenceSolutionDomainOptionViewModel)sender).IndependentAxesVMs[0].AxisRangeVM;
                }
                // todo: must this fire on ANY property, or is there a specific one we can listen to, as above?
                this.OnPropertyChanged("IsTimeFrequencyDomain");
            };

            FluenceSolutionDomainTypeOptionVM.PropertyChanged              += updateSolutionDomain;
            AbsorbedEnergySolutionDomainTypeOptionVM.PropertyChanged       += updateSolutionDomain;
            PhotonHittingDensitySolutionDomainTypeOptionVM.PropertyChanged += updateSolutionDomain;

            MapTypeOptionVM = new OptionViewModel <MapType>(
                "Map Type",
                new[]
            {
                MapType.Fluence,
                MapType.AbsorbedEnergy,
                MapType.PhotonHittingDensity
            });

            MapTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "SelectedValues")
                {
                    OnPropertyChanged("IsFluence");
                    OnPropertyChanged("IsAbsorbedEnergy");
                    OnPropertyChanged("IsPhotonHittingDensity");
                    OnPropertyChanged("IsTimeFrequencyDomain");
                    UpdateAvailableOptions();
                }
            };

            ForwardSolverTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                OnPropertyChanged("ForwardSolver");
                OnPropertyChanged("IsGaussianForwardModel");
                OnPropertyChanged("IsMultiRegion");
                OnPropertyChanged("IsSemiInfinite");
                TissueInputVM = GetTissueInputVM(IsMultiRegion ? "MultiLayer" : "SemiInfinite");
                UpdateAvailableOptions();
                OnPropertyChanged("IsTimeFrequencyDomain");
            };

            ExecuteFluenceSolverCommand = new RelayCommand(() => ExecuteFluenceSolver_Executed(null, null));
        }
        public SpectralMappingViewModel()
        {
#if WHITELIST
            ScatteringTypeVM = new OptionViewModel <ScatteringType>("Scatterer Type", true, WhiteList.ScatteringTypes);
#else
            ScatteringTypeVM = new OptionViewModel <ScatteringType>("Scatterer Type", true);
#endif
            ScatteringTypeVM.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "SelectedValue" && SelectedTissue != null)//SelectedTissue.ScattererType != ScatteringTypeVM.SelectedValue)
                {
                    SelectedTissue.Scatterer = SolverFactory.GetScattererType(ScatteringTypeVM.SelectedValue);
                    var bindableScatterer = SelectedTissue.Scatterer as INotifyPropertyChanged;
                    if (bindableScatterer != null)
                    {
                        bindableScatterer.PropertyChanged += (s, a) => UpdateOpticalProperties();
                    }
                    //LM - Temporary Fix to reset the tissue type after a new scatterer is created
                    if (SelectedTissue.ScattererType == ScatteringType.PowerLaw)
                    {
                        PowerLawScatterer myScatterer = (PowerLawScatterer)SelectedTissue.Scatterer;
                        myScatterer.SetTissueType(SelectedTissue.TissueType);
                    }
                    ScatteringTypeName = SelectedTissue.Scatterer.GetType().FullName;
                }
                OnPropertyChanged("Scatterer");
                UpdateOpticalProperties();
            };

            WavelengthRangeVM = new RangeViewModel(new DoubleRange(650.0, 1000.0, 36), "nm", IndependentVariableAxis.Wavelength, "Wavelength Range");

            Tissues = new List <Tissue>
            {
                new Tissue(TissueType.Skin),
                new Tissue(TissueType.BrainWhiteMatter),
                new Tissue(TissueType.BrainGrayMatter),
                new Tissue(TissueType.BreastPreMenopause),
                new Tissue(TissueType.BreastPostMenopause),
                new Tissue(TissueType.Liver),
                new Tissue(TissueType.IntralipidPhantom),
                //new Tissue(TissueType.PolystyreneSpherePhantom),
                new Tissue(TissueType.Custom)
            };

            BloodConcentrationVM = new BloodConcentrationViewModel();
            #region DC notes 1
            // DC NOTES on how to propagate the correct hemoglobin instances into BloodConcentrationVM:
            // Upon setting SelectedTissue (below), we internally update the BloodConcentrationVM hemoglobin references
            // This is the simplest solution, but maybe violates SOC...(see SelectedTissue property for details)
            // A second alternative way would be to override AfterPropertyChanged (see AfterPropertyChanged method below)
            #endregion
            BloodConcentrationVM.PropertyChanged += (sender, args) => UpdateOpticalProperties();

            SelectedTissue = Tissues.First();
            ScatteringTypeVM.SelectedValue = SelectedTissue.ScattererType; // forces update to all bindings established in hanlder for ScatteringTypeVM.PropertyChanged above
            ScatteringTypeName             = SelectedTissue.GetType().FullName;
            OpticalProperties = new OpticalProperties(0.01, 1, 0.8, 1.4);
            Wavelength        = 650;

            PlotMuaSpectrumCommand  = new RelayCommand(PlotMuaSpectrum_Executed);
            PlotMuspSpectrumCommand = new RelayCommand(PlotMuspSpectrum_Executed);

            Commands.SD_SetWavelength.Executed += (snder, args) => // updates when solution domain is involved in spectral feedback
            {
                // Wavelength = (double) args.Parameter; // this will ping-pong back to FS (stack overflow), so repeating setter logic here:
                _wavelength = (double)args.Parameter;
                UpdateOpticalProperties();
                // Commands.Spec_UpdateWavelength.Execute(_wavelength); (don't do this)

                this.OnPropertyChanged("Wavelength");
            };
        }
        public InverseSolverViewModel()
        {
            _showOpticalProperties = true;
            _useSpectralPanelData = false;

            _allRangeVMs = new[] { new RangeViewModel { Title = Resources.Strings.IndependentVariableAxis_Rho } };

            SolutionDomainTypeOptionVM = new SolutionDomainOptionViewModel("Solution Domain", SolutionDomainType.ROfRho);
            SolutionDomainTypeOptionVM.EnableMultiAxis = false;
            SolutionDomainTypeOptionVM.AllowMultiAxis = false;

            Action<double> updateSolutionDomainWithWavelength = wv =>
            {
                var wvAxis = SolutionDomainTypeOptionVM.ConstantAxesVMs.FirstOrDefault(axis => axis.AxisType == IndependentVariableAxis.Wavelength);
                if (wvAxis != null)
                {
                    wvAxis.AxisValue = wv;
                }
            };

            SolutionDomainTypeOptionVM.PropertyChanged += (sender, args) => 
            {
                if (args.PropertyName == "UseSpectralInputs")
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (args.PropertyName == "IndependentAxesVMs")
                {
                    var useSpectralPanelDataAndNotNull = UseSpectralPanelData && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null;

                    AllRangeVMs = (from i in Enumerable.Range(0, SolutionDomainTypeOptionVM.IndependentVariableAxisOptionVM.SelectedValues.Length)
                                        orderby i descending // descending so that wavelength takes highest priority, then time/time frequency, then space/spatial frequency
                                        select useSpectralPanelDataAndNotNull && SolutionDomainTypeOptionVM.IndependentVariableAxisOptionVM.SelectedValues[i] == IndependentVariableAxis.Wavelength
                                             ? SolverDemoViewModel.Current.SpectralMappingVM.WavelengthRangeVM // bind to same instance, not a copy
                                             : SolutionDomainTypeOptionVM.IndependentAxesVMs[i].AxisRangeVM).ToArray();

                    // if the independent axis is wavelength, then hide optical properties (because they come from spectral panel)
                    ShowOpticalProperties = !_allRangeVMs.Any(value => value.AxisType == IndependentVariableAxis.Wavelength);

                    // update solution domain wavelength constant if applicable
                    if (useSpectralPanelDataAndNotNull && SolutionDomainTypeOptionVM.ConstantAxesVMs.Any(axis => axis.AxisType == IndependentVariableAxis.Wavelength))
                    {
                        updateSolutionDomainWithWavelength(SolverDemoViewModel.Current.SpectralMappingVM.Wavelength);
                    }
                }
            };

#if WHITELIST
            MeasuredForwardSolverTypeOptionVM = new OptionViewModel<ForwardSolverType>(
                "Forward Model Engine",false, WhiteList.InverseForwardSolverTypes);
#else
             MeasuredForwardSolverTypeOptionVM = new OptionViewModel<ForwardSolverType>(
                "Forward Model Engine",false);
#endif
            
#if WHITELIST 
            InverseForwardSolverTypeOptionVM = new OptionViewModel<ForwardSolverType>("Inverse Model Engine",false, WhiteList.InverseForwardSolverTypes);
#else
            InverseForwardSolverTypeOptionVM = new OptionViewModel<ForwardSolverType>("Inverse Model Engine", false);
#endif
            InverseForwardSolverTypeOptionVM.PropertyChanged += (sender, args) =>
                OnPropertyChanged("InverseForwardSolver");

            OptimizerTypeOptionVM = new OptionViewModel<OptimizerType>("Optimizer Type", true);
            OptimizerTypeOptionVM.PropertyChanged += (sender, args) =>
                OnPropertyChanged("Optimizer");

            InverseFitTypeOptionVM = new OptionViewModel<InverseFitType>("Optimization Parameters", true);

            MeasuredOpticalPropertyVM = new OpticalPropertyViewModel() { Title = "" };
            InitialGuessOpticalPropertyVM = new OpticalPropertyViewModel() { Title = "" };
            ResultOpticalPropertyVM = new OpticalPropertyViewModel() { Title = "" };

            SimulateMeasuredDataCommand = new RelayCommand(() => SimulateMeasuredDataCommand_Executed(null, null));
            CalculateInitialGuessCommand = new RelayCommand(() => CalculateInitialGuessCommand_Executed(null, null));
            SolveInverseCommand = new RelayCommand(() => SolveInverseCommand_Executed(null, null));
            
            Commands.Spec_UpdateWavelength.Executed += (sender, args) =>
            {
                //need to get the value from the checkbox in case UseSpectralPanelData has not yet been updated
                if (SolutionDomainTypeOptionVM != null)
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (UseSpectralPanelData && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null)
                {
                    updateSolutionDomainWithWavelength(SolverDemoViewModel.Current.SpectralMappingVM.Wavelength);
                }
            };
            Commands.Spec_UpdateOpticalProperties.Executed += (sender, args) =>
            {
                //need to get the value from the checkbox in case UseSpectralPanelData has not yet been updated
                if (SolutionDomainTypeOptionVM != null)
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (UseSpectralPanelData && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null)
                {
                    //if (IsMultiRegion && MultiRegionTissueVM != null)
                    //{
                    //    MultiRegionTissueVM.RegionsVM.ForEach(region =>
                    //        ((dynamic)region).OpticalPropertyVM.SetOpticalProperties(
                    //            SolverDemoViewModel.Current.SpectralMappingVM.OpticalProperties));
                    //}
                    //else
                    if (MeasuredOpticalPropertyVM != null)
                    {
                        MeasuredOpticalPropertyVM.SetOpticalProperties(SolverDemoViewModel.Current.SpectralMappingVM.OpticalProperties);
                    }
                }
            };
        }
        public ForwardSolverViewModel()
        {
            _showOpticalProperties = true;
            _useSpectralPanelData  = false;

            _allRangeVMs = new[] { new RangeViewModel {
                                       Title = Resources.Strings.IndependentVariableAxis_Rho
                                   } };

#if WHITELIST
            ForwardSolverTypeOptionVM = new OptionViewModel <ForwardSolverType>("Forward Model", false, WhiteList.ForwardSolverTypes);
#else
            ForwardSolverTypeOptionVM = new OptionViewModel <ForwardSolverType>("Forward Model", false);
#endif
            SolutionDomainTypeOptionVM = new SolutionDomainOptionViewModel("Solution Domain", SolutionDomainType.ROfRho);

            ForwardAnalysisTypeOptionVM = new OptionViewModel <ForwardAnalysisType>("Model/Analysis Output", true);

            ForwardSolverTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                OnPropertyChanged("IsGaussianForwardModel");
                OnPropertyChanged("ForwardSolver");
                OnPropertyChanged("IsMultiRegion");
                OnPropertyChanged("IsSemiInfinite");
                TissueInputVM = GetTissueInputVM(IsMultiRegion ? "MultiLayer" : "SemiInfinite");
                if (SolutionDomainTypeOptionVM != null)
                {
                    if (ForwardSolverTypeOptionVM.SelectedValue == ForwardSolverType.TwoLayerSDA)
                    {
                        SolutionDomainTypeOptionVM.AllowMultiAxis    = false;
                        SolutionDomainTypeOptionVM.UseSpectralInputs = false;
                    }
                    SolutionDomainTypeOptionVM.EnableMultiAxis           = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                    SolutionDomainTypeOptionVM.EnableSpectralPanelInputs = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                }
                if (ForwardAnalysisTypeOptionVM != null)
                {
                    if (ForwardSolverTypeOptionVM.SelectedValue == ForwardSolverType.TwoLayerSDA)
                    {
                        ForwardAnalysisTypeOptionVM.Options[ForwardAnalysisType.R].IsSelected = true;
                    }
                    ForwardAnalysisTypeOptionVM.Options[ForwardAnalysisType.dRdMua].IsEnabled  = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                    ForwardAnalysisTypeOptionVM.Options[ForwardAnalysisType.dRdMusp].IsEnabled = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                    ForwardAnalysisTypeOptionVM.Options[ForwardAnalysisType.dRdG].IsEnabled    = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                    ForwardAnalysisTypeOptionVM.Options[ForwardAnalysisType.dRdN].IsEnabled    = ForwardSolverTypeOptionVM.SelectedValue != ForwardSolverType.TwoLayerSDA;
                }
            };
            ForwardSolverTypeOptionVM.SelectedValue = ForwardSolverType.PointSourceSDA; // force the model choice here?

            Action <double> updateSolutionDomainWithWavelength = wv =>
            {
                var wvAxis = SolutionDomainTypeOptionVM.ConstantAxesVMs.FirstOrDefault(axis => axis.AxisType == IndependentVariableAxis.Wavelength);
                if (wvAxis != null)
                {
                    wvAxis.AxisValue = wv;
                }
            };

            SolutionDomainTypeOptionVM.PropertyChanged += (sender, args) =>
            {
                if (args.PropertyName == "UseSpectralInputs")
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (args.PropertyName == "IndependentAxesVMs")
                {
                    var useSpectralPanelDataAndNotNull = SolutionDomainTypeOptionVM.UseSpectralInputs && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null;

                    AllRangeVMs = (from i in Enumerable.Range(0, SolutionDomainTypeOptionVM.IndependentVariableAxisOptionVM.SelectedValues.Length)
                                   orderby i descending                                                        // descending so that wavelength takes highest priority, then time/time frequency, then space/spatial frequency
                                   select useSpectralPanelDataAndNotNull&& SolutionDomainTypeOptionVM.IndependentVariableAxisOptionVM.SelectedValues[i] == IndependentVariableAxis.Wavelength
                                             ? SolverDemoViewModel.Current.SpectralMappingVM.WavelengthRangeVM // bind to same instance, not a copy
                                             : SolutionDomainTypeOptionVM.IndependentAxesVMs[i].AxisRangeVM).ToArray();

                    // if the independent axis is wavelength, then hide optical properties (because they come from spectral panel)
                    ShowOpticalProperties = !_allRangeVMs.Any(value => value.AxisType == IndependentVariableAxis.Wavelength);

                    // update solution domain wavelength constant if applicable
                    if (useSpectralPanelDataAndNotNull && SolutionDomainTypeOptionVM.ConstantAxesVMs.Any(axis => axis.AxisType == IndependentVariableAxis.Wavelength))
                    {
                        updateSolutionDomainWithWavelength(SolverDemoViewModel.Current.SpectralMappingVM.Wavelength);
                    }
                }
            };

            ExecuteForwardSolverCommand = new RelayCommand(() => ExecuteForwardSolver_Executed(null, null));

            Commands.Spec_UpdateWavelength.Executed += (sender, args) =>
            {
                //need to get the value from the checkbox in case UseSpectralPanelData has not yet been updated
                if (SolutionDomainTypeOptionVM != null)
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (UseSpectralPanelData && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null)
                {
                    updateSolutionDomainWithWavelength(SolverDemoViewModel.Current.SpectralMappingVM.Wavelength);
                }
            };
            Commands.Spec_UpdateOpticalProperties.Executed += (sender, args) =>
            {
                //need to get the value from the checkbox in case UseSpectralPanelData has not yet been updated
                if (SolutionDomainTypeOptionVM != null)
                {
                    UseSpectralPanelData = SolutionDomainTypeOptionVM.UseSpectralInputs;
                }
                if (UseSpectralPanelData && SolverDemoViewModel.Current != null && SolverDemoViewModel.Current.SpectralMappingVM != null)
                {
                    if (IsMultiRegion && MultiRegionTissueVM != null)
                    {
                        MultiRegionTissueVM.RegionsVM.ForEach(region =>
                                                              ((dynamic)region).OpticalPropertyVM.SetOpticalProperties(
                                                                  SolverDemoViewModel.Current.SpectralMappingVM.OpticalProperties));
                    }
                    else if (OpticalPropertyVM != null)
                    {
                        OpticalPropertyVM.SetOpticalProperties(SolverDemoViewModel.Current.SpectralMappingVM.OpticalProperties);
                    }
                }
            };
        }