private static ValidationResult ValidateDetectorInput(SimulationInput si) { if (((si.Options.Databases == null) || (si.Options.Databases.Count() < 1)) && (si.DetectorInputs.Count() < 1)) { return(new ValidationResult( false, "No detector inputs specified and no database to be written", "Make sure list of DetectorInputs is not empty or null if no databases are to be written")); } // black list of unimplemented detectors foreach (var detectorInput in si.DetectorInputs) { if (detectorInput.TallyDetails.IsNotImplementedYet) { return(new ValidationResult( false, "DetectorInput not implemented yet:" + detectorInput.ToString(), "Please omit " + detectorInput.ToString() + " from DetectorInput list")); } } return(new ValidationResult( true, "DetectorInput must be valid", "")); }
/// <summary> /// Output from a Monte Carlo simulation /// </summary> /// <param name="si">SimulationInput</param> /// <param name="detectorResults">list of IDetector</param> public SimulationOutput(SimulationInput si, IList <IDetector> detectorResults) { int count = 1; Input = si; ResultsDictionary = new Dictionary <String, IDetector>(); foreach (var detector in detectorResults) { try { ResultsDictionary.Add(detector.Name, detector); } catch (Exception e) { Console.WriteLine("Problem adding detector results to dictionary.\n\nDetails:\n\n" + e + "\n"); if (e is ArgumentException) { Console.WriteLine("detector with that name already exists in dictionary\n"); Console.WriteLine("Adding detector with name = " + detector.Name + count + " instead.\n"); string newName = detector.Name + count; ResultsDictionary.Add(newName, detector); ++count; } } } //ResultsDictionary = detectorResults.ToDictionary(d => d.Name); _detectorResults = detectorResults; }
/// <summary> /// Master of call validation methods. Calls methods to validate source, /// tissue and detector definitions. /// </summary> /// <param name="input">SimulationInput to be validated</param> /// <returns>ValidationResult with IsValid bool set and message about error if false</returns> public static ValidationResult ValidateInput(SimulationInput input) { var validations = new Func <SimulationInput, ValidationResult>[] { si => ValidateN(si.N), si => ValidateSourceInput(si.SourceInput, si.TissueInput), si => ValidateTissueInput(si.TissueInput), si => ValidateDetectorInput(si), si => ValidateCombinedInputParameters(si), si => ValidateCurrentIncapabilities(si) }; foreach (var validation in validations) { var tempResult = validation(input); if (!tempResult.IsValid) { return(tempResult); } } return(new ValidationResult(true, "Simulation input is valid")); }
/// <summary> /// Method checks SimulationInput against current incapabilities of the code. /// </summary> /// <param name="input">SimulationInput</param> /// <returns>ValidationResult</returns> private static ValidationResult ValidateCurrentIncapabilities(SimulationInput input) { if (input.Options.AbsorptionWeightingType == AbsorptionWeightingType.Continuous) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsNotImplementedForCAW) { return(new ValidationResult( false, "The use of Continuous Absorption Weighting is not implemented for one of the infile detectors", "Modify AbsorptionWeightingType to Discrete")); } } } if (input.Options.AbsorptionWeightingType == AbsorptionWeightingType.Discrete) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsNotImplementedForDAW) { return(new ValidationResult( false, "The use of Discrete Absorption Weighting with path length type detectors not implemented yet", "Modify AbsorptionWeightingType to Continuous")); } } } foreach (var detectorInput in input.DetectorInputs) { // can only run dMC detectors with 1 perturbed region for the present if (detectorInput.TallyType.Contains("dMCdROfRhodMua")) { return(dMCdROfRhodMuaDetectorInputValidation.ValidateInput(detectorInput)); } if (detectorInput.TallyType.Contains("dMCdROfRhodMus")) { return(dMCdROfRhodMusDetectorInputValidation.ValidateInput(detectorInput)); } // check that number in blood volume list matches number of tissue subregions if (detectorInput.TallyType.Contains("ReflectedDynamicMTOfRhoAndSubregionHist")) { return(ReflectedDynamicMTOfRhoAndSubregionHistDetectorInputValidation.ValidateInput(detectorInput, input.TissueInput.Regions.Count())); } if (detectorInput.TallyType.Contains("ReflectedDynamicMTOfXAndYAndSubregionHist")) { return(ReflectedDynamicMTOfXAndYAndSubregionHistDetectorInputValidation.ValidateInput(detectorInput, input.TissueInput.Regions.Count())); } if (detectorInput.TallyType.Contains("TransmittedDynamicMTOfRhoAndSubregionHist")) { return(TransmittedDynamicMTOfRhoAndSubregionHistDetectorInputValidation.ValidateInput(detectorInput, input.TissueInput.Regions.Count())); } if (detectorInput.TallyType.Contains("TransmittedDynamicMTOfXAndYAndSubregionHist")) { return(TransmittedDynamicMTOfXAndYAndSubregionHistDetectorInputValidation.ValidateInput(detectorInput, input.TissueInput.Regions.Count())); } if (detectorInput.TallyType.Contains("SurfaceFiber")) { return(SurfaceFiberDetectorInputValidation.ValidateInput(detectorInput)); } } return(new ValidationResult( true, "Detector definitions are consistent with current capabilities")); }
/// <summary> /// This method checks the input against combined combinations of options /// and source, tissue, detector definitions. /// </summary> /// <param name="input">input to be validated</param> /// <returns>ValidationResult with IsValid set and error message if false</returns> private static ValidationResult ValidateCombinedInputParameters(SimulationInput input) { // check that absorption weighting type set to analog and RR weight threshold != 0.0 if ((input.Options.AbsorptionWeightingType == AbsorptionWeightingType.Analog) && input.Options.RussianRouletteWeightThreshold != 0.0) { return(new ValidationResult( false, "Russian Roulette cannot be employed with Analog absorption weighting is specified", "With Analog absorption weighting, set Russian Roulette weight threshold = 0.0")); } // check that if single ellipsoid tissue specified and (r,z) detector specified, // that (1) ellipsoid is centered at x=0, y=0, (2) ellipsoid is cylindrically symmetric (dx=dy) if (input.TissueInput is SingleEllipsoidTissueInput) { foreach (var detectorInput in input.DetectorInputs) { var ellipsoid = (EllipsoidTissueRegion)((SingleEllipsoidTissueInput)input.TissueInput). EllipsoidRegion; if (detectorInput.TallyDetails.IsCylindricalTally && (ellipsoid.Center.X != 0.0) && (ellipsoid.Center.Y != 0.0)) { return(new ValidationResult( false, "Ellipsoid must be centered at (x,y)=(0,0) for cylindrical tallies", "Change ellipsoid center to (0,0) or specify non-cylindrical type tally")); } if (detectorInput.TallyDetails.IsCylindricalTally && (ellipsoid.Dx != ellipsoid.Dy)) { return(new ValidationResult( false, "Ellipsoid must have Dx=Dy for cylindrical tallies", "Change ellipsoid.Dx to be = to Dy or specify non-cylindrical type tally")); } if (detectorInput.TallyType == TallyType.ROfFx) { return(new ValidationResult( false, "R(fx) tallies assume a homogeneous or layered tissue geometry", "Change tissue type to be homogeneous or layered")); } } } // check that if single voxel or single infinite cylinder tissue specified, // cannot specify (r,z) detector if ((input.TissueInput is SingleVoxelTissueInput) || (input.TissueInput is SingleInfiniteCylinderTissueInput)) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsCylindricalTally) { return(new ValidationResult( false, "Cannot use Single Voxel Tissue for cylindrical tallies", "Change detector inputs to specify non-cylindrical type tallies")); } if (detectorInput.TallyType == TallyType.ROfFx) { return(new ValidationResult( false, "R(fx) tallies assume a homogeneous or layered tissue geometry", "Change tissue type to be homogeneous or layered")); } } } // check that if bounding volume tissue specified, the ATotalBoundingVolumeTissueInput detector needs // to be specified if (input.TissueInput is BoundingCylinderTissueInput) { if (!input.DetectorInputs.Any(d => d.TallyType == TallyType.ATotalBoundingVolume)) { return(new ValidationResult( false, "BoundingCylinderTissueInput needs associated detector ATotalBoundingVolume to be defined", "Add ATotalBoundingVolumeDetectorInput to detector inputs")); } } if (input.SourceInput is DirectionalPointSourceInput) { var source = (DirectionalPointSourceInput)input.SourceInput; if (source.Direction != new Direction(0, 0, 1)) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsCylindricalTally) { return(new ValidationResult( false, "If source is angled, cannot define cylindrically symmetric detectors", "Change detector to Cartesian equivalent or define source to be normal")); } } } } foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsTransmittanceTally && (input.TissueInput is MultiLayerTissueInput)) { if ((((dynamic)detectorInput).FinalTissueRegionIndex == 0)) { return(new ValidationResult( false, "Transmittance detectors with MultiLayerTissues cannot detect in tissue region 0", "Change FinalTissueRegionIndex to be index of air below tissue (index >= 2)")); } } } return(new ValidationResult( true, "Input options or tissue/detector combinations are valid", "")); }
/// <summary> /// Class that takes in SimulationInput and methods to initialize and execute Monte Carlo simulation /// </summary> /// <param name="input">SimulationInput</param> public MonteCarloSimulation(SimulationInput input) { _outputPath = ""; // all field/property defaults should be set here _input = input; var result = SimulationInputValidation.ValidateInput(_input); if (result.IsValid == false) { throw new ArgumentException(result.ValidationRule + (!string.IsNullOrEmpty(result.Remarks) ? "; " + result.Remarks : "")); } _numberOfPhotons = input.N; AbsorptionWeightingType = input.Options.AbsorptionWeightingType; // CKH add 12/14/09 TrackStatistics = input.Options.TrackStatistics; if (TrackStatistics) { _simulationStatistics = new SimulationStatistics(); } _rng = RandomNumberGeneratorFactory.GetRandomNumberGenerator( input.Options.RandomNumberGeneratorType, input.Options.Seed); this.SimulationIndex = input.Options.SimulationIndex; _tissue = TissueFactory.GetTissue(input.TissueInput, input.Options.AbsorptionWeightingType, input.Options.PhaseFunctionType, input.Options.RussianRouletteWeightThreshold); _source = SourceFactory.GetSource(input.SourceInput, _rng); // instantiate vb (and associated detectors) for each vb group _virtualBoundaryController = new VirtualBoundaryController(new List <IVirtualBoundary>()); List <VirtualBoundaryType> dbVirtualBoundaries = input.Options.Databases.Select(db => db.GetCorrespondingVirtualBoundaryType()).ToList(); foreach (var vbType in EnumHelper.GetValues <VirtualBoundaryType>()) { IEnumerable <IDetectorInput> detectorInputs = null; switch (vbType) { case VirtualBoundaryType.DiffuseReflectance: default: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsReflectanceTally).ToList(); break; case VirtualBoundaryType.DiffuseTransmittance: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsTransmittanceTally).ToList(); break; case VirtualBoundaryType.SpecularReflectance: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsSpecularReflectanceTally).ToList(); break; case VirtualBoundaryType.GenericVolumeBoundary: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsVolumeTally).ToList(); break; case VirtualBoundaryType.SurfaceRadiance: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsInternalSurfaceTally).ToList(); break; case VirtualBoundaryType.pMCDiffuseReflectance: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IspMCReflectanceTally).ToList(); break; case VirtualBoundaryType.BoundingCylinderVolume: detectorInputs = input.DetectorInputs.Where(d => d.TallyDetails.IsBoundingVolumeTally).ToList(); break; } // make sure VB Controller has at least diffuse reflectance and diffuse transmittance // may change this in future if tissue OnDomainBoundary changes if ((detectorInputs.Count() > 0) || (vbType == VirtualBoundaryType.DiffuseReflectance) || (vbType == VirtualBoundaryType.DiffuseTransmittance) || (dbVirtualBoundaries.Any(vb => vb == vbType))) { var detectors = DetectorFactory.GetDetectors(detectorInputs, _tissue, _rng); var detectorController = DetectorControllerFactory.GetDetectorController(vbType, detectors, _tissue); // var detectorController = new DetectorController(detectors); var virtualBoundary = VirtualBoundaryFactory.GetVirtualBoundary(vbType, _tissue, detectorController); _virtualBoundaryController.VirtualBoundaries.Add(virtualBoundary); } } // needed? //_detectorControllers = _virtualBoundaryController.VirtualBoundaries.Select(vb=>vb.DetectorController).ToList(); // set doPMC flag if (input.Options.Databases.Any(d => d.IspMCDatabase())) { doPMC = true; } _isCancelled = false; _isRunning = false; _resultsAvailable = false; }
//[DllImport(@"Vts.MonteCarlo.Unmanaged.dll", EntryPoint = "RunTest")] //public static extern void RunUnmanagedMC(ref UnmanagedPhoton unmanagedPhoton, // ref UnmanagedTissue unmanagedTissue, ref UnmanagedPerturb unmanagedPerturb, // ref UnmanagedOutput unmanagedOutput); public UnmanagedMonteCarloSimulation(SimulationInput input) : base(input) { }
/// <summary> /// This method checks the input against combined combinations of options /// and source, tissue, detector definitions. /// </summary> /// <param name="input">input to be validated</param> /// <returns>ValidationResult with IsValid set and error message if false</returns> private static ValidationResult ValidateCombinedInputParameters(SimulationInput input) { // check that absorption weighting type set to analog and RR weight threshold != 0.0 if ((input.Options.AbsorptionWeightingType == AbsorptionWeightingType.Analog) && input.Options.RussianRouletteWeightThreshold != 0.0) { return(new ValidationResult( false, "Russian Roulette cannot be employed with Analog absorption weighting is specified", "With Analog absorption weighting, set Russian Roulette weight threshold = 0.0")); } // check that if single ellipsoid tissue specified and (r,z) detector specified, // that (1) ellipsoid is centered at x=0, y=0, (2) ellipsoid is cylindrically symmetric (dx=dy) if (input.TissueInput is SingleEllipsoidTissueInput) { foreach (var detectorInput in input.DetectorInputs) { var ellipsoid = (EllipsoidTissueRegion)((SingleEllipsoidTissueInput)input.TissueInput). EllipsoidRegion; if (detectorInput.TallyDetails.IsCylindricalTally && (ellipsoid.Center.X != 0.0) && (ellipsoid.Center.Y != 0.0)) { return(new ValidationResult( false, "Ellipsoid must be centered at (x,y)=(0,0) for cylindrical tallies", "Change ellipsoid center to (0,0) or specify non-cylindrical type tally")); } if (detectorInput.TallyDetails.IsCylindricalTally && (ellipsoid.Dx != ellipsoid.Dy)) { return(new ValidationResult( false, "Ellipsoid must have Dx=Dy for cylindrical tallies", "Change ellipsoid.Dx to be = to Dy or specify non-cylindrical type tally")); } if (detectorInput.TallyType == "ROfFx") { return(new ValidationResult( false, "R(fx) tallies assume a homogeneous or layered tissue geometry", "Change tissue type to be homogeneous or layered")); } } } // check that if single voxel or single infinite cylinder tissue specified, // cannot specify (r,z) detector if ((input.TissueInput is SingleVoxelTissueInput) || (input.TissueInput is SingleInfiniteCylinderTissueInput)) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsCylindricalTally) { return(new ValidationResult( false, "Cannot use Single Voxel Tissue for cylindrical tallies", "Change detector inputs to specify non-cylindrical type tallies")); } if (detectorInput.TallyType == "ROfFx") { return(new ValidationResult( false, "R(fx) tallies assume a homogeneous or layered tissue geometry", "Change tissue type to be homogeneous or layered")); } } } // check that if non-normal source defined, that detectors defined are not cylindrical tallies // this could be greatly expanded, just an initial start if (input.SourceInput is DirectionalPointSourceInput) { var source = (DirectionalPointSourceInput)input.SourceInput; if (source.Direction != new Direction(0, 0, 1)) { foreach (var detectorInput in input.DetectorInputs) { if (detectorInput.TallyDetails.IsCylindricalTally) { return(new ValidationResult( false, "If source is angled, cannot define cylindrically symmetric detectors", "Change detector to Cartesian equivalent or define source to be normal")); } } } } return(new ValidationResult( true, "Input options or tissue/detector combinations are valid", "")); }