コード例 #1
0
 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);
     }
 }
コード例 #2
0
 public static TransmissionLoss ClosestTransmissionLoss(this Scenario scenario, Geo geo, Mode mode)
 {
     var closest = (from ap in scenario.AnalysisPoints
                    from tl in ap.TransmissionLosses
                    where tl.Modes[0].IsAcousticallyEquivalentTo(mode)
                    let d = geo.DistanceKilometers(ap.Geo)
                    orderby d
                    select new { d, tl }).FirstOrDefault();
     return closest != null ? closest.tl : null;
 }
コード例 #3
0
        public override void CalculateTransmissionLoss(Platform platform, Mode mode, Radial radial, BottomProfile bottomProfile, SedimentType sedimentType, double windSpeed, IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial)
        {
            var sourceDepth = platform.Depth;
            var frequency = (float)Math.Sqrt(mode.HighFrequency * mode.LowFrequency);
            if (mode.Depth.HasValue) sourceDepth += mode.Depth.Value;
            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);

            // Derived Parameters
            // ==================
            // Note: All the specific calculations given in the comments below assume a frequency of 1kHz
            // lambda is wavelength, in meters
            var lambda = ReferenceSoundSpeed / frequency;
            // if dz < 1m round dz down to either [1/10, 1/5, 1/4 or 1/2] m  ... or multiples of 10^-n of these numbers
            //                                  = [1     2    2.5 or 5  ] x 0.1m  "   " ...
            // if dz > 1m round dz down to either [1     2    2.5    5  ] m  ... or multiples of 10^+n of these numbers
            // var fixpoints = new List<double> { 1, 2, 2.5, 5 };
            // dz = 0.1 * lambda
            var dz = RelativeDepthResolution * lambda;
            // make dz a 'pretty' number
            //dz = Fix2X10pN(dz, fixpoints);

            // ndz is the depth decimation factor
            // MinimumOutputDepthResolution is 10m
            // dz is 0.1 * lambda (dz = 0.15 for a 1 kHz signal, 'pretty' dz = 0.2 @ 1kHz)
            // so ndz = (10 / 0.2) = 50 @ 1kHz
            // this means that we will only output every 50 computational depth cells, giving us a depth
            // resolution of 50 * 0.2m = 10m @ 1kHz which is what we want it to be.  Outstanding.
            var ndz = (int)Math.Max(1.0, Math.Floor(MinimumOutputDepthResolution / dz));

            //  similar for dr and assoc. grid decimation
            // RelativeRangeResolution is 2, so with our 'pretty' dz = 0.2, dr = 0.4
            var dr = RelativeRangeResolution * dz;
            // make dr a 'pretty' number, in this case 0.25
            //dr = Fix2X10pN(dr, fixpoints);
            // ndr is the range decimation factor
            // MinimumOutputRangeResolution is 10m
            // dr is 0.25 * lambda, so (10 / 0.25) gives us an ndr of 40
            // this means that we will only output every 40 computational range cells, giving us a range
            // resolution of 40 * 0.25m = 10m @ 1kHz which is what we want it to be.  Outstanding.
            var ndr = (int)Math.Max(1, Math.Floor(MinimumOutputRangeResolution / dr));

            //  attenuation layer (round up to nearest dz)
            var sedimentLambda = sedimentType.CompressionWaveSpeed / frequency;
            var sedimentLayerDz = Math.Ceiling(LastLayerThickness * sedimentLambda / dz) * dz;
            var attenuationLayerDz = Math.Ceiling(AttenuationLayerThickness * sedimentLambda / dz) * dz;
            var maxSubstrateDepth = bottomProfile.MaxDepth + sedimentLayerDz;
            var zstep = dz * ndz;
            var zmplt = Math.Ceiling((bottomProfile.MaxDepth + 2 * zstep) / zstep) * zstep;
            // Maximum Depth for PE calc ->  zmax 
            //  zmax is the z-limit for the PE calc from top of the water column to the bottom of the last substrate layer 
            // (including the attentuation layer if, as recommended, this is included)
            var zmax = maxSubstrateDepth + attenuationLayerDz;
            var envFileName = radial.BasePath + ".env";
            //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}",
            //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
            //                radial.TransmissionLoss.AnalysisPoint.Geo,
            //                radial.TransmissionLoss.Modes[0].ModeName,
            //                radial.Bearing, zmplt);

            using (var envFile = new StreamWriter(envFileName, false))
            {
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "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:0.000000}\t{1:0.000000}\t{2:0.000000}\t\tf [Frequency (Hz)], zs [Source Depth (m)], zrec0 [First receiever depth (m)]",
                                  frequency,
                                  sourceDepth,
                                  0.1));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t\t\trmax[Max range (m)], dr [Range resolution (m)], ndr [Range grid decimation factor]",
                                  mode.MaxPropagationRadius + (dr * ndr),
                                  dr,
                                  ndr));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1:0.000000}\t{2}\t{3:0.000000}\tzmax [Max computational depth (m)], dz [Depth resolution (m)], ndz [Depth grid decimation factor], zmplot [Maximum depth to plot (m)]",
                                  zmax,
                                  dz,
                                  ndz,
                                  zmplt));
                envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.000000}\t{1}\t{2}\t{3:0.000000}\t\tc0 [Reference sound speed (m/s)], np [Number of terms in Padé expansion], ns [Number of stability constraints], rs [Maximum range of stability constraints (m)]",
                                  ReferenceSoundSpeed,
                                  PadeExpansionTerms,
                                  StabilityConstraints,
                                  StabilityConstraintMaxRange));
                // todo: different stuff goes here for RAMSGeo

                // bathymetry data
                var first = true;
                foreach (var profilePoint in bottomProfile.Profile)
                {
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture,
                                                    "{0:0.000000}\t{1:0.000000}{2}",
                                                    profilePoint.Range * 1000,
                                                    profilePoint.Depth,
                                                    first ? "\t\t\t\t\tbathymetry data [range (m), depth (m)]" : ""));
                    first = false;
                }
                envFile.WriteLine("-1\t-1");

                // range-dependent environment profiles
                var firstRangeProfile = true;
                foreach (var rangeProfileTuple in soundSpeedProfilesAlongRadial)
                {
                    // Range of profile only written for second and subsequent profiles
                    if (!firstRangeProfile) envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.#}\t\t\t\t\t\t\tProfile range (m)", rangeProfileTuple.Item1 * 1000));

                    var firstSoundSpeedProfile = true;
                    foreach (var profilePoint in rangeProfileTuple.Item2.Data)
                    {
                        if (double.IsNaN(profilePoint.SoundSpeed)) break;
                        envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}{2}",
                                          profilePoint.Depth,
                                          profilePoint.SoundSpeed,
                                          firstSoundSpeedProfile ? "\t\t\t\t\tsound speed profile in water [depth (m), sound speed (m/s)]" : ""));
                        firstSoundSpeedProfile = false;
                    }
                    envFile.WriteLine("-1\t-1");

                    // todo: RAMGeo and RAMSGeo also support sediment layers, as well as range-dependent sediment, neither of which is not yet supported by ESME
                    // If sediment layers are ever supported, put a loop like for the sound speed profile above
                    // A sediment layer is analogous to a sound speed profile point
                    // For range-dependent sediment, the sediment samples have to be at the same ranges as the sound speed profiles
                    // so we might want to change the API to include sediment properties in what is the current range and sound speed profile tuple
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive sound speed profile in substrate [depth (m), sound speed (m/s)]", 0.0, sedimentType.CompressionWaveSpeed));
                    envFile.WriteLine("-1\t-1");
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tdensity profile in substrate [depth (m), rhob (g/cm³)]", 0.0, sedimentType.Density));
                    envFile.WriteLine("-1\t-1");
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}\t\t\t\t\t\tcompressive attenuation profile in substrate [depth (m), attnp (db/lambda)]", 0.0, 0.0));
                    envFile.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}", attenuationLayerDz, 40));
                    envFile.WriteLine("-1\t-1");
                    firstRangeProfile = false;
                }
            }
            var tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(envFileName));
            //Debug.WriteLine(string.Format("Env File: {0} temp path: {1}", envFileName, tempDirectory));
            if (Directory.Exists(tempDirectory))
            {
                var files = Directory.GetFiles(tempDirectory, "*.*");
                foreach (var file in files) File.Delete(file);
                Directory.Delete(tempDirectory, true);
            } else if (File.Exists(tempDirectory)) File.Delete(tempDirectory);
            Directory.CreateDirectory(tempDirectory);
            File.Copy(envFileName, Path.Combine(tempDirectory, "ramgeo.in"));
            using (var steerableArrayFile = new StreamWriter(Path.Combine(tempDirectory, "sra.in"), false))
            {
                // From http://www.activefrance.com/Antennas/Introduction%20to%20Phased%20Array%20Design.pdf
                // theta3 = 3dB beam width, in degrees
                // emitterSize = size of emitter array, in meters
                // theta3 = (0.886 * lambda / arrayLength) * 180 / pi
                // so, doing the algebra and solving for arrayLength, you get:
                // emitterSize = (0.886 * lambda) / (theta3 * (pi / 180))
                var emitterSize = (0.886 * lambda) / (mode.VerticalBeamWidth * (Math.PI / 180.0));
                var emitterCount = (int)(emitterSize / (dz * 2));
                var emitterSpacing = 1.0;
                var weights = new List<double> { 1 };
                if (emitterCount > 1)
                {
                    emitterSpacing = emitterSize / (emitterCount - 1);
                    // chebyshev window calculations for relative emitter strength across the array
                    var discreteFourierTransform = new MathNet.Numerics.IntegralTransforms.Algorithms.DiscreteFourierTransform();
                    var r0 = Math.Pow(10, mode.SideLobeAttenuation / 20.0);
                    var n = emitterCount - 1;
                    var a = Complex.Cosh((1.0 / n) * Acosh(r0));
                    var am = new Complex[n];
                    for (var m = 0; m < n; m++) am[m] = a * Complex.Cos(Math.PI * m / n);
                    var wm = new Complex[n];
                    var sign = 1;
                    for (var i = 0; i < n; i++)
                    {
                        if (am[i].Magnitude > 1) wm[i] = sign * Complex.Cosh(n * Acosh(am[i]));
                        else wm[i] = sign * Complex.Cos(n * Complex.Acos(am[i]));
                        sign *= -1;
                    }
                    discreteFourierTransform.BluesteinInverse(wm, FourierOptions.Default);
                    weights = wm.Select(e => e.Real).ToList();
                    weights[0] /= 2;
                    weights.Add(weights[0]);
                    var maxWeight = weights.Max();
                    for (var i = 0; i < weights.Count; i++) weights[i] /= maxWeight;
                }
                steerableArrayFile.WriteLine("{0}\t{1}\t{2}", emitterCount, emitterSpacing, mode.DepressionElevationAngle);
                for (var i = 0; i < emitterCount; i++) steerableArrayFile.WriteLine("{0}", weights[i]);
            }
            //File.Copy(Path.Combine(AssemblyLocation, "sra.in"), Path.Combine(tempDirectory, "sra.in"));
            //Debug.WriteLine(string.Format("Env File: {0} copied to: {1}", envFileName, tempDirectory));
            // Now that we've got the files ready to go, we can launch bellhop to do the actual calculations
            var ramProcess = new Process
            {
                StartInfo = new ProcessStartInfo(Path.Combine(AssemblyLocation, "RAMGeo.exe"))
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardInput = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    WorkingDirectory = tempDirectory
                }
            };
            if (radial.IsDeleted) throw new RadialDeletedByUserException();
            ramProcess.Start();
            try
            {
                ramProcess.PriorityClass = ProcessPriorityClass.Idle;
            }
            catch (InvalidOperationException) { }
            //ramProcess.BeginOutputReadLine();
            while (!ramProcess.HasExited)
            {
                if (radial.IsDeleted)
                {
                    ramProcess.Kill();
                    throw new RadialDeletedByUserException();
                }
                Thread.Sleep(20);
            }
            var ramOutput = ramProcess.StandardOutput.ReadToEnd();
            var ramError = ramProcess.StandardError.ReadToEnd();
            if (ramProcess.ExitCode != 0)
            {
                Debug.WriteLine("RAMGeo process for radial {0} exited with error code {1:X}", radial.BasePath, ramProcess.ExitCode);
                Debug.WriteLine(ramError);
                Directory.Delete(tempDirectory, true);
                return;
            }
            //File.Delete(Path.Combine(tempDirectory, "ramgeo.in"));
            //File.Delete(radial.BasePath + ".grid");
            //File.Move(Path.Combine(tempDirectory, "tl.grid"), radial.BasePath + ".grid");
            //File.Delete(radial.BasePath + ".line");
            //File.Move(Path.Combine(tempDirectory, "tl.line"), radial.BasePath + ".line");
            //File.Delete(radial.BasePath + ".pgrid");
            //File.Move(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid");
            //File.Delete(radial.BasePath + ".sra");
            //File.Move(Path.Combine(tempDirectory, "sra.in"), radial.BasePath + ".sra");

            using (var writer = new StreamWriter(radial.BasePath + ".bty")) writer.Write(bottomProfile.ToBellhopString());
            if (File.Exists(Path.Combine(tempDirectory, "p.grid")))
            {
                var pressures = ReadPGrid(Path.Combine(tempDirectory, "p.grid"));
                File.Copy(Path.Combine(tempDirectory, "p.grid"), radial.BasePath + ".pgrid", true);
                //File.Delete(radial.BasePath + ".pgrid");
                if (pressures.Count == 0)
                {
                    Debug.WriteLine("Temp directory: " + tempDirectory);
                    Debug.WriteLine("RAMGeo stdout: " + ramOutput);
                    Debug.WriteLine("RAMGeo stderr: " + ramError);
                    Directory.Delete(tempDirectory, true);
                    return;
                }
                var rangeCount = pressures.Count;
                var depthCount = pressures[0].Length;
                var rr = new double[rangeCount];
                var rd = new double[depthCount];
                for (var rangeIndex = 0; rangeIndex < rr.Length; rangeIndex++) rr[rangeIndex] = (rangeIndex + 1) * dr * ndr;
                for (var depthIndex = 0; depthIndex < rd.Length; depthIndex++) rd[depthIndex] = depthIndex * zstep;
                //Debug.WriteLine("Scenario: '{0}' Mode: '{2}' Analysis point: {1} Bearing: {3}, zmplt: {4}, zstep: {5}, maxDepth: {6}, fileName: {7}, reqDepthCells: {8}, actualDepthCells: {9}",
                //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
                //                radial.TransmissionLoss.AnalysisPoint.Geo,
                //                radial.TransmissionLoss.Modes[0].ModeName,
                //                radial.Bearing,
                //                zmplt,
                //                zstep,
                //                rd.Last(),
                //                Path.GetFileNameWithoutExtension(radial.BasePath),
                //                zmplt / zstep,
                //                depthCount);
                var shadeFile = new ShadeFile(sourceDepth, frequency, rd, rr, pressures);
                shadeFile.Write(radial.BasePath + ".shd");
                //BellhopOutput.WriteShadeFile(radial.BasePath + ".shd", sourceDepth, frequency, rd, rr, pressures);
            }
            else
            {
                //Debug.WriteLine("Scenario: {0} Analysis point: {1} Mode {2} Bearing {3}",
                //                radial.TransmissionLoss.AnalysisPoint.Scenario.Name,
                //                radial.TransmissionLoss.AnalysisPoint.Geo,
                //                radial.TransmissionLoss.Modes[0].ModeName,
                //                radial.Bearing);
                //Debug.WriteLine("p.grid file not found in RAMGeo output directory");
            }
            Directory.Delete(tempDirectory, true);
            //Debug.WriteLine(string.Format("Env File: {0} temp directory deleted: {1}", envFileName, tempDirectory));
        }
コード例 #4
0
 public abstract void CalculateTransmissionLoss(Platform platform,
                                       Mode mode,
                                       Radial radial,
                                       BottomProfile bottomProfile,
                                       SedimentType sedimentType,
                                       double windSpeed,
                                       IList<Tuple<double, SoundSpeedProfile>> soundSpeedProfilesAlongRadial);
コード例 #5
0
 void AddMode(Source source, string name, bool isNew, float frequency = 1000f, float depth = 0f, float maxPropagationRadius = 25000f)
 {
     var mode = new Mode
     {
         ActiveTime = 1f,
         Depth = depth,
         DepressionElevationAngle = 0f,
         HighFrequency = frequency,
         LowFrequency = frequency,
         MaxPropagationRadius = maxPropagationRadius,
         ModeName = name,
         ModeType = null,
         PulseInterval = new TimeSpan(0, 0, 0, 30),
         PulseLength = new TimeSpan(0, 0, 0, 0, 500),
         RelativeBeamAngle = 0,
         Source = source,
         SourceLevel = 200,
         VerticalBeamWidth = 180f,
         HorizontalBeamWidth = 90,
         IsNew = isNew,
         TransmissionLossPluginType = Globals.PluginManagerService[PluginType.TransmissionLossCalculator][PluginSubtype.Bellhop].DefaultPlugin.PluginIdentifier.Type,
     };
     source.Modes.Add(mode);
     //source.Platform.Scenario.Add(mode);
     source.Platform.Scenario.UpdateAnalysisPoints();
 }
コード例 #6
0
 internal void Log(Mode mode, string message) { LogBase(new LogEntry(mode), message); }
コード例 #7
0
        public ModePropertiesViewModel(Mode mode)
        {
            _editedMode = mode;
            _originalMode = new Mode(mode);
            ModeName = _editedMode.ModeName;
            ModeType = _editedMode.ModeType;
            Depth = _editedMode.Depth;
            SourceLevel = _editedMode.SourceLevel;
            LowFrequency = _editedMode.LowFrequency;
            HighFrequency = _editedMode.HighFrequency;
            PulseIntervalString = _editedMode.PulseInterval != null ? ((TimeSpan)_editedMode.PulseInterval).ToString(TimeSpanFormatString) : null;
            PulseLengthString = _editedMode.PulseLength != null ? ((TimeSpan)_editedMode.PulseLength).ToString(TimeSpanFormatString) : null;
            HorizontalBeamWidth = _editedMode.HorizontalBeamWidth;
            VerticalBeamWidth = _editedMode.VerticalBeamWidth;
            DepressionElevationAngle = _editedMode.DepressionElevationAngle;
            RelativeBeamAngle = _editedMode.RelativeBeamAngle;
            MaxPropagationRadius = _editedMode.MaxPropagationRadius;
            ValidRadialCounts = new List<string> { "Auto", "4", "8", "16", "32", "64", "128" };
            RadialCountString = _editedMode.RadialCount == 0 ? ValidRadialCounts[0] : _editedMode.RadialCount.ToString(CultureInfo.InvariantCulture);
            SideLobeAttenuation = _editedMode.SideLobeAttenuation;

            AvailableTransmissionLossEngines.AddRange(from key in Globals.PluginManagerService[PluginType.TransmissionLossCalculator].Keys
                                                      select (TransmissionLossCalculatorPluginBase)Globals.PluginManagerService[PluginType.TransmissionLossCalculator][key].DefaultPlugin);

            SelectedTransmissionLossEngine = _editedMode.GetTransmissionLossPlugin(Globals.PluginManagerService);

            _propertyObserver = new PropertyObserver<ModePropertiesViewModel>(this)
                .RegisterHandler(p => p.SelectedTransmissionLossEngine, () => { });
            WindowTitle = string.Format("Mode properties: {0}", _editedMode.ModeName);
            AddValidationRules(
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "Depth",
                    Description = "Cannot be negative",
                    IsRuleValid = (target, rule) => target.Depth.HasValue && target.Depth.Value >= 0.0f,
                }
                ,
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "SourceLevel",
                    Description = "Must be greater than zero",
                    IsRuleValid = (target, rule) => target.SourceLevel > 0,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "HighFrequency",
                    Description = "Must be greater than zero",
                    IsRuleValid = (target, rule) => target.HighFrequency > 0,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "PulseIntervalString",
                    Description = "Must be a valid, non-negative time span value in the format hh:mm:ss.fff where 00 <= hh <= 23; 00 <= mm <= 59; 00 <= ss <= 59; 000 <= fff <= 999",
                    IsRuleValid = (target, rule) =>
                    {
                        if (string.IsNullOrEmpty(target.PulseIntervalString)) return false;
                        TimeSpan timeSpan;
                        var isOK = TimeSpan.TryParseExact(target.PulseIntervalString, TimeSpanFormatString, null, out timeSpan);
                        return isOK && timeSpan.Ticks > 0;
                    },
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "PulseLengthString",
                    Description = "Must be a valid, non-negative time span value in the format hh:mm:ss.fff where 00 <= hh <= 23; 00 <= mm <= 59; 00 <= ss <= 59; 000 <= fff <= 999",
                    IsRuleValid = (target, rule) =>
                    {
                        if (string.IsNullOrEmpty(target.PulseLengthString)) return false;
                        TimeSpan timeSpan;
                        var isOK = TimeSpan.TryParseExact(target.PulseLengthString, TimeSpanFormatString, null, out timeSpan);
                        return isOK && timeSpan.Ticks > 0;
                    },
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "RelativeBeamAngle",
                    Description = "Must be between -180 and 180, inclusive",
                    IsRuleValid = (target, rule) => -180 <= target.RelativeBeamAngle && target.RelativeBeamAngle <= 180,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "HorizontalBeamWidth",
                    Description = "Must be a positive value less than or equal to 360",
                    IsRuleValid = (target, rule) => 0 < target.HorizontalBeamWidth && target.HorizontalBeamWidth <= 360,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "VerticalBeamWidth",
                    Description = "Must be a positive value less than or equal to 180",
                    IsRuleValid = (target, rule) => 0 < target.VerticalBeamWidth && target.VerticalBeamWidth <= 180,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "DepressionElevationAngle",
                    Description = "Must be between -90 and 90, inclusive",
                    IsRuleValid = (target, rule) => -90 <= target.DepressionElevationAngle && target.DepressionElevationAngle <= 90,
                },
                new ValidationRule<ModePropertiesViewModel>
                {
                    PropertyName = "MaxPropagationRadius",
                    Description = "Must be a positive value",
                    IsRuleValid = (target, rule) => target.MaxPropagationRadius > 0,
                });
        }
コード例 #8
0
 /// <summary>
 /// True if this mode is acoustically equivalent to the other mode
 /// Acoustic equivalence means that the following are ALL TRUE
 /// depths are within 0.001 m
 /// vertical beam widths are within 0.1 deg
 /// depression/elevation angles are within 0.1 deg
 /// high frequencies are within 0.1 Hz
 /// low frequencies are within 0.1 Hz
 /// 
 /// As of 22 Feb 2013, the transmission loss plugins selected to 
 /// compute the sound fields must also be identical
 /// </summary>
 /// <param name="other"></param>
 /// <returns></returns>
 public bool IsAcousticallyEquivalentTo(Mode other)
 {
     var myDepth = Source.Platform.Depth;
     if (Depth.HasValue) myDepth += Depth.Value;
     var otherDepth = other.Source.Platform.Depth;
     if (other.Depth.HasValue) otherDepth += other.Depth.Value;
     if (Math.Abs(myDepth - otherDepth) > 0.001) return false;
     if (Math.Abs(VerticalBeamWidth - other.VerticalBeamWidth) > 0.1) return false;
     if (Math.Abs(DepressionElevationAngle - other.DepressionElevationAngle) > 0.1) return false;
     if (Math.Abs(HighFrequency - other.HighFrequency) > 0.1) return false;
     if (Math.Abs(LowFrequency - other.LowFrequency) > 0.1) return false;
     return TransmissionLossPluginType == other.TransmissionLossPluginType;
 }
コード例 #9
0
 void ModeProperties(Mode mode)
 {
     var vm = new ModePropertiesViewModel(mode);
     var result = Globals.VisualizerService.ShowDialog("ModePropertiesWindowView", vm);
     if (!(result.HasValue && result.Value)) return;
     mode.LowFrequency = mode.HighFrequency;
     Scenario.UpdateAnalysisPoints();
 }
コード例 #10
0
        public void PlatformBehaviorToKML()
        {
            var jaxOpsArea = new GeoArray(new Geo(29.3590, -79.2195),
                                          new Geo(31.1627, -79.2195),
                                          new Geo(31.1627, -81.2789),
                                          new Geo(30.1627, -81.2789),
                                          new Geo(29.3590, -80.8789),
                                          new Geo(29.3590, -79.2195));

            var platform = new Platform
            {
                PlatformName = "Test Platform",
                Perimeter = jaxOpsArea,
                Depth = 0,
                IsRandom = true,
                TrackType = TrackType.PerimeterBounce,
                Sources = new ObservableList<Source>(),
                Speed = 20,
            };
            var source = new Source
            {
                SourceName = "Test Source",
                Modes = new ObservableList<Mode>(),
                Platform = platform,
            };
            platform.Sources.Add(source);
            var mode = new Mode
            {
                ModeName = "Test Mode",
                PulseInterval = new TimeSpan(0, 0, 0, 10),
                PulseLength = new TimeSpan(0, 0, 0, 0, 500),
                Depth = 5,
                HighFrequency = 1000,
                LowFrequency = 1000,
                DepressionElevationAngle = 10,
                VerticalBeamWidth = 90,
                SourceLevel = 200,
                Source = source,
            };
            source.Modes.Add(mode);

            var behavior = new PlatformBehavior(platform, new TimeSpan(0, 0, 0, 1), 86400);
#if true
            var kml = new KMLRoot();
            var folder = new Folder("Jacksonville");
            jaxOpsArea.Placemark.name = "Jacksonville OpArea";
            jaxOpsArea.Placemark.Snippet = "The operational area";
            jaxOpsArea.Placemark.Snippet.maxLines = 1;
            folder.Add(jaxOpsArea.Placemark);

#if true
            var timeStep = 0;
            foreach (var state in behavior.PlatformStates)
            {
                if (timeStep % 100 == 0)
                {
                    state.PlatformLocation.Location.Placemark.name = string.Format("TimeStep {0}", timeStep);
                    folder.Add(state.PlatformLocation.Location.Placemark);
                }
                timeStep++;
            }
#else
            result.Placemark.name = "Platform track";
            result.Placemark.Snippet = "The track of the platform";
            result.Placemark.Snippet.maxLines = 1;
            result.Placemark.Geometry.AltitudeMode = AltitudeMode.clampedToGround;
            folder.Add(result.Placemark);
#endif

            kml.Document.Add(folder);

            var savePath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments), "Platform Behavior Tests", "PlatformBehavior.kml");
            Debug.WriteLine("Saving KML...");
            kml.Save(savePath);
#endif
        }
コード例 #11
0
 void RecalculateMode(Mode mode)
 {
     if (Globals.MessageBoxService.ShowYesNo(string.Format("Are you sure you want to recalculate all transmission losses for the mode \"{0}\"?", mode.ModeName), MessageBoxImage.Warning) !=
         MessageBoxResult.Yes) return;
     foreach (var transmissionLoss in mode.TransmissionLosses) transmissionLoss.Recalculate();
 }
コード例 #12
0
 void DeleteMode(Mode mode)
 {
     if (Globals.MessageBoxService.ShowYesNo(string.Format("Are you sure you want to delete the mode \"{0}\"?", mode.ModeName), MessageBoxImage.Warning) != MessageBoxResult.Yes) return;
     mode.Delete();
     OnPropertyChanged("CanPlaceAnalysisPoint");
     OnPropertyChanged("IsSaveScenarioCommandEnabled");
 }
コード例 #13
0
 async void ModeBoundToLayer(Mode mode)
 {
     if (!mode.IsNew) return;
     mode.IsNew = false;
     ((LayerControl)mode.LayerControl).Select();
     await Task.Delay(50);
     ((LayerControl)mode.LayerControl).Edit();
 }
コード例 #14
0
 public Mode(Mode mode) { Copy(mode); }
コード例 #15
0
 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);
 }
コード例 #16
0
 void Copy(Mode mode)
 {
     PSMModeGuid = mode.PSMModeGuid;
     ModeName = mode.ModeName;
     ModeType = mode.ModeType;
     ActiveTime = mode.ActiveTime;
     Depth = mode.Depth;
     SourceLevel = mode.SourceLevel;
     LowFrequency = mode.LowFrequency;
     HighFrequency = mode.HighFrequency;
     PulseInterval = mode.PulseInterval;
     PulseLength = mode.PulseLength;
     HorizontalBeamWidth = mode.HorizontalBeamWidth;
     VerticalBeamWidth = mode.VerticalBeamWidth;
     DepressionElevationAngle = mode.DepressionElevationAngle;
     RelativeBeamAngle = mode.RelativeBeamAngle;
     MaxPropagationRadius = mode.MaxPropagationRadius;
     TransmissionLossPluginType = mode.TransmissionLossPluginType;
     RadialCount = mode.RadialCount;
     Source = mode.Source;
 }
コード例 #17
0
        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();
        }
コード例 #18
0
 public int GetHashCode(Mode obj) { return obj.GetHashCode(); }
コード例 #19
0
 static void UpdateFootprintMapLayer(Mode mode, PlatformState state, OverlayShapeMapLayer mapLayer)
 {
     mapLayer.Clear();
     var initialGeo = state.PlatformLocation.Location;
     var footprintArcStartBearing = state.PlatformLocation.Course + mode.RelativeBeamAngle - (Math.Abs(mode.HorizontalBeamWidth / 2));
     var footprintArcEndBearing = state.PlatformLocation.Course + mode.RelativeBeamAngle + (Math.Abs(mode.HorizontalBeamWidth / 2));
     var geos = new List<Geo>();
     if (mode.HorizontalBeamWidth < 360) geos.Add(initialGeo);
     for (var arcPointBearing = footprintArcStartBearing; arcPointBearing < footprintArcEndBearing; arcPointBearing++) geos.Add(initialGeo.Offset(Geo.MetersToRadians(mode.MaxPropagationRadius), Geo.DegreesToRadians(arcPointBearing)));
     geos.Add(initialGeo.Offset(Geo.MetersToRadians(mode.MaxPropagationRadius), Geo.DegreesToRadians(footprintArcEndBearing)));
     geos.Add(mode.HorizontalBeamWidth < 360 ? initialGeo : initialGeo.Offset(Geo.MetersToRadians(mode.MaxPropagationRadius), Geo.DegreesToRadians(footprintArcStartBearing)));
     mapLayer.AddPolygon(geos);
     mapLayer.Done();
 }