public Radial(Radial radial) : this() { IsCalculated = radial.IsCalculated; CalculationStarted = new DateTime(radial.CalculationStarted.Ticks); CalculationCompleted = new DateTime(radial.CalculationCompleted.Ticks); Bearing = radial.Bearing; Length = radial.Length; }
/// <summary> /// Update a TransmissionLoss to reflect the modes that it currently contains. /// If there are no modes associated with the TransmissionLoss, delete it. /// If the max number of radials among the associated modes has changed, /// or if the max calculation radius of the associated modes is larger than the existing radials, /// recalculate the TransmissionLoss /// </summary> /// <param name="transmissionLoss"></param> static void Update(this TransmissionLoss transmissionLoss) { if (transmissionLoss.Modes == null || transmissionLoss.Modes.Count == 0) { // If there are no modes, the TransmissionLoss is not needed transmissionLoss.Delete(); return; } // Get the maximum radial count called for by the associated modes in the TransmissionLoss var modeRadialCount = transmissionLoss.Modes.Max(m => m.RadialCount); // Get the maximum propagation radius called for by the associated modes in the TransmissionLoss var modeMaxRadius = transmissionLoss.Modes.Max(m => m.MaxPropagationRadius); // Check to see if none of the modes have defined a radial count. If not, use the default values modeRadialCount = modeRadialCount > 0 ? modeRadialCount : modeMaxRadius <= 10000 ? 8 : 16; // If there are any radials already defined, and if the count of those radials is the same as the max radial count // and the length of all radials is greater than or equal to the required max radius, this TransmissionLoss is valid if (transmissionLoss.Radials != null && transmissionLoss.Radials.Count == modeRadialCount && transmissionLoss.Radials.All(radial => radial.Length >= modeMaxRadius)) { // Redraw the map layers to display the new TransmissionLoss as it should be Globals.Dispatcher.InvokeIfRequired(transmissionLoss.UpdateMapLayers); return; } // If the list of radials is null, create a list if (transmissionLoss.Radials == null) transmissionLoss.Radials = new ObservableList<Radial>(); // Create a list of required bearings so we can delete any existing radials that are no longer required var requiredBearings = new List<double>(); // Loop through all the radials we will need to satisfy the current mode requirements for (var radialIndex = 0; radialIndex < modeRadialCount; radialIndex++) { // Calculate the bearing of the next radial we will need to have var radialBearing = (360.0 / modeRadialCount) * radialIndex; // Add the current bearing to the list of required bearings requiredBearings.Add(radialBearing); // Find the radial in the current set that matches the bearing, if there is one var currentRadial = transmissionLoss.Radials.FirstOrDefault(r => Math.Abs(r.Bearing - radialBearing) < double.Epsilon); // If there is a radial that matches the bearing AND that radial is too short to meet the current length requirements if (currentRadial != null && currentRadial.Length < modeMaxRadius) { //Debug.WriteLine(string.Format("Deleting too-short radial [{0}] from mode [{1}] at {2}", currentRadial, transmissionLoss.Modes.First(), (Geo)transmissionLoss.AnalysisPoint.Geo)); // Delete the radial currentRadial.Delete(); // Pretend that we didn't find a matching radial, so we will create one below currentRadial = null; } // If we found a radial that matches the bearing and length requirements, check the next one if (currentRadial != null) continue; // We didn't find a radial that matches the bearing and length requirements, so create one now var radial = new Radial { TransmissionLoss = transmissionLoss, CalculationCompleted = DateTime.MaxValue, CalculationStarted = DateTime.MaxValue, Bearing = radialBearing, Length = modeMaxRadius, IsCalculated = false, }; //Debug.WriteLine(string.Format("Adding new radial [{0}] to mode [{1}] at {2}", radial, transmissionLoss.Modes.First(), (Geo)transmissionLoss.AnalysisPoint.Geo)); // Add the new Radial to the TransmissionLoss //transmissionLoss.Radials.Add(radial); // Queue the new Radial for calculation Globals.TransmissionLossCalculatorService.Add(radial); } // Delete any radials in the current TransmissionLoss that are no longer required // Debug.WriteLine(string.Format("Deleting now-unused radial [{0}] from mode [{1}] at {2}", r.ToString(), transmissionLoss.Modes.First(), (Geo)transmissionLoss.AnalysisPoint.Geo)); transmissionLoss.Radials.FindAll(r => !requiredBearings.Contains(r.Bearing)).ForEach(r => r.Delete()); // Redraw the map layers to display the new TransmissionLoss as it should be Globals.Dispatcher.InvokeIfRequired(transmissionLoss.UpdateMapLayers); }
void Copy(Scenario scenario) { Name = scenario.Name; Comments = scenario.Comments; ShowAllAnalysisPoints = scenario.ShowAllAnalysisPoints; ShowAllPerimeters = scenario.ShowAllPerimeters; ShowAllSpecies = scenario.ShowAllSpecies; StartTime = new TimeSpan(scenario.StartTime.Ticks); Duration = new TimeSpan(scenario.Duration.Ticks); TimePeriod = (TimePeriod)scenario.TimePeriod; Location = scenario.Location; Wind = scenario.Wind; SoundSpeed = scenario.SoundSpeed; Sediment = scenario.Sediment; Bathymetry = scenario.Bathymetry; // Here we map the old perimeter to the new perimeter so that the copied platform gets the proper perimeter var perimeterMap = new Dictionary<Guid, Guid>(); foreach (var perimeter in scenario.Perimeters) { var newPerimeter = new Perimeter(perimeter) { Scenario = this }; perimeterMap.Add(perimeter.Guid, newPerimeter.Guid); Perimeters.Add(newPerimeter); } var modeMap = new Dictionary<Guid, Guid>(); var allModes = new List<Mode>(); foreach (var platform in scenario.Platforms) { var newPlatform = new Platform(platform) { Scenario = this }; // Make sure the new perimeter gets the proper copied perimeter from the original scenario if (platform.Perimeter != null) newPlatform.Perimeter = Perimeters.Find(p => p.Guid == perimeterMap[platform.Perimeter.Guid]); Platforms.Add(newPlatform); foreach (var source in platform.Sources) { var newSource = new Source(source) { Platform = newPlatform }; newPlatform.Sources.Add(newSource); foreach (var mode in source.Modes) { var newMode = new Mode(mode) { Source = newSource }; modeMap.Add(mode.Guid, newMode.Guid); newSource.Modes.Add(newMode); allModes.Add(newMode); } } } foreach (var analysisPoint in scenario.AnalysisPoints) { var newAnalysisPoint = new AnalysisPoint(analysisPoint) { Scenario = this }; AnalysisPoints.Add(newAnalysisPoint); foreach (var transmissionLoss in analysisPoint.TransmissionLosses) { var newTransmissionLoss = new TransmissionLoss { AnalysisPoint = newAnalysisPoint, LayerSettings = new LayerSettings(transmissionLoss.LayerSettings) }; foreach (var mode in transmissionLoss.Modes) newTransmissionLoss.Modes.Add(allModes.Find(m => m.Guid == modeMap[mode.Guid])); newAnalysisPoint.TransmissionLosses.Add(newTransmissionLoss); foreach (var radial in transmissionLoss.Radials) { var newRadial = new Radial(radial) { TransmissionLoss = newTransmissionLoss }; newTransmissionLoss.Radials.Add(newRadial); newRadial.CopyFiles(radial); } } } foreach (var species in scenario.ScenarioSpecies) { var newSpecies = new ScenarioSpecies(species) { Scenario = this }; ScenarioSpecies.Add(newSpecies); newSpecies.CopyFiles(species); } }
public abstract void CalculateTransmissionLoss(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial);
protected void CalculateTransmissionLossInternal(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial, bool createArrivalsFile) { var depthCellCount = (int)Math.Ceiling(bottomProfile.MaxDepth / DepthCellSize); var rangeCellCount = (int)Math.Ceiling(mode.MaxPropagationRadius / RangeCellSize); var startProfile = soundSpeedProfilesAlongRadial[0].Item2; var sourceDepth = platform.Depth; var frequency = (float)Math.Sqrt(mode.HighFrequency * mode.LowFrequency); if (mode.Depth.HasValue) sourceDepth += mode.Depth.Value; var maxCalculationDepthMeters = bottomProfile.MaxDepth * 1.01; var directoryPath = Path.GetDirectoryName(radial.BasePath); if (directoryPath == null) throw new NullReferenceException("radial.BasePath does not point to a valid directory"); if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath); using (var envFile = new StreamWriter(radial.BasePath + ".env", false)) { envFile.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}", radial.TransmissionLoss.AnalysisPoint.Scenario.Name, radial.TransmissionLoss.AnalysisPoint.Geo, radial.TransmissionLoss.Modes[0].ModeName, radial.Bearing); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", frequency)); envFile.WriteLine("1"); // was NMEDIA in gui_genbellhopenv.m envFile.WriteLine(UseSurfaceReflection ? "'QFLT'" : "'QVLT'"); //if (depthCellCount < 5) throw new BathymetryTooShallowException("Error: Maximum depth of transect (" + maxCalculationDepthMeters + " meters) less than minimum required for transmission loss calculations.\nPlease choose a different location for this transect."); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "0, 0.0, {0}", startProfile.Data[startProfile.Data.Count - 1].Depth)); foreach (var soundSpeedSample in startProfile.Data) envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} 0.0 1.0 0.0 0.0", soundSpeedSample.Depth, soundSpeedSample.SoundSpeed)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "'A*' 0.0")); // A = Acoustic halfspace, * = read bathymetry file 'BTYFIL', 0.0 = bottom roughness (currently ignored) envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3} {4} {5} /", maxCalculationDepthMeters, sedimentType.CompressionWaveSpeed, sedimentType.ShearWaveSpeed, sedimentType.Density, sedimentType.LossParameter, 0)); // Source and Receiver Depths and Ranges envFile.WriteLine("1"); // Number of Source Depths envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} /", sourceDepth)); // source depth envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", depthCellCount)); // Number of Receiver Depths envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "0.0 {0} /", maxCalculationDepthMeters)); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", rangeCellCount)); // Number of receiver ranges envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "0.0 {0} /", mode.MaxPropagationRadius / 1000.0)); envFile.WriteLine(createArrivalsFile ? "'a'" : "'I'"); envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", RayCount)); // Number of beams var verticalHalfAngle = mode.VerticalBeamWidth / 2; var angle1 = mode.DepressionElevationAngle - verticalHalfAngle; var angle2 = mode.DepressionElevationAngle + verticalHalfAngle; envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} /", angle1, angle2)); // Beam fan half-angles (negative angles are toward the surface envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "0.0 {0} {1}", maxCalculationDepthMeters, (mode.MaxPropagationRadius / 1000.0) * 1.01)); // step zbox(meters) rbox(km) } using (var sspFile = new StreamWriter(radial.BasePath + ".ssp", false)) { if (soundSpeedProfilesAlongRadial.Count == 1) soundSpeedProfilesAlongRadial.Add(Tuple.Create(Geo.RadiansToKilometers(radial.Segment.LengthRadians), new SoundSpeedProfile(soundSpeedProfilesAlongRadial[0].Item2))); sspFile.WriteLine("{0}", soundSpeedProfilesAlongRadial.Count); foreach (var rangeProfileTuple in soundSpeedProfilesAlongRadial) sspFile.Write(string.Format(CultureInfo.InvariantCulture, "{0,-10:0.###}", rangeProfileTuple.Item1)); sspFile.WriteLine(); //sspFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0,-10:0.###}{1,-10:0.###}{2,-10:0.###}", 0.0, bottomProfile.Profile[bottomProfile.Profile.Count / 2].Range, bottomProfile.Profile[bottomProfile.Profile.Count - 1].Range)); for (var depthIndex = 0; depthIndex < startProfile.Data.Count; depthIndex++) { foreach (var rangeProfileTuple in soundSpeedProfilesAlongRadial) sspFile.Write(string.Format(CultureInfo.InvariantCulture, "{0,-10:0.###}", rangeProfileTuple.Item2.Data[depthIndex].SoundSpeed)); sspFile.WriteLine(); } //sspFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0,-10:0.###}{1,-10:0.###}{2,-10:0.###}", startProfile.Data[depthIndex].SoundSpeed, middleProfile.Data[depthIndex].SoundSpeed, endProfile.Data[depthIndex].SoundSpeed)); } using (var trcFile = new StreamWriter(radial.BasePath + ".trc", false)) { var topReflectionCoefficients = GenerateReflectionCoefficients(windSpeed, frequency); trcFile.WriteLine(topReflectionCoefficients.GetLength(0)); for (var rowIndex = 0; rowIndex < topReflectionCoefficients.GetLength(0); rowIndex++) trcFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} ", topReflectionCoefficients[rowIndex, 0], topReflectionCoefficients[rowIndex, 1], topReflectionCoefficients[rowIndex, 2])); } using (var writer = new StreamWriter(radial.BasePath + ".bty")) writer.Write(bottomProfile.ToBellhopString()); // Now that we've got the files ready to go, we can launch bellhop to do the actual calculations var bellhopProcess = new Process { StartInfo = new ProcessStartInfo(Path.Combine(AssemblyLocation, "bellhop.exe"), radial.Filename) { CreateNoWindow = true, UseShellExecute = false, RedirectStandardInput = false, RedirectStandardOutput = true, RedirectStandardError = true, WorkingDirectory = directoryPath } }; if (radial.IsDeleted) throw new RadialDeletedByUserException(); bellhopProcess.Start(); try { bellhopProcess.PriorityClass = ProcessPriorityClass.Idle; } catch (InvalidOperationException) {} //bellhopProcess.BeginOutputReadLine(); while (!bellhopProcess.HasExited) { if (radial.IsDeleted) { bellhopProcess.Kill(); throw new RadialDeletedByUserException(); } Thread.Sleep(20); } if (bellhopProcess.ExitCode == 0) return; var bellhopOutput = bellhopProcess.StandardOutput.ReadToEnd(); var bellhopError = bellhopProcess.StandardError.ReadToEnd(); Debug.WriteLine("Bellhop process for radial {0} exited with error code {1:X}", radial.BasePath, bellhopProcess.ExitCode); Debug.WriteLine("Bellhop stdout: " + bellhopOutput); Debug.WriteLine("Bellhop stderr: " + bellhopError); radial.CleanupFiles(); }
public override void CalculateTransmissionLoss(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial) { CalculateTransmissionLossInternal(platform, mode, radial, bottomProfile, sedimentType, windSpeed, soundSpeedProfilesAlongRadial, false); }
public void CopyFiles(Radial radial) { var files = Directory.GetFiles(Path.GetDirectoryName(radial.BasePath), Path.GetFileNameWithoutExtension(radial.BasePath) + ".*"); foreach (var file in files) File.Copy(file, BasePath + Path.GetExtension(file)); }