diff --git a/GeoMagSharp/Calculator.cs b/GeoMagSharp/Calculator.cs
index 8b3aeb9..516de98 100644
--- a/GeoMagSharp/Calculator.cs
+++ b/GeoMagSharp/Calculator.cs
@@ -1,20 +1,24 @@
/****************************************************************************
- * File: GeoMagBGGM.cs
- * Description: routines to handle bggm coefficients file and calculate
- * field values
- * Akowlegements: Ported from the C++ model code created by the British Geological Survey
- * Website: http://www.geomag.bgs.ac.uk/data_service/directionaldrilling/bggm.html
- * Warnings: This code can be used with the IGRF, WMM, or BGGM coeficent file. The BGGM
- * coeficient file is Commerically avalable from the British Geological Survey
- * and is not distributed with this project. Please contcact the BGS for more information.
- *
+ * File: Calculator.cs
+ * Description: Routines to calculate magnetic field values from
+ * spherical harmonic coefficient files
+ * Reference: Based on the NOAA World Magnetic Model (WMM) algorithm
+ * https://www.ncei.noaa.gov/products/world-magnetic-model
+ * Compatibility: This code can be used with IGRF, WMM, or other standard
+ * coefficient files in COF or DAT format.
* Current version: 2.21
- * ****************************************************************************/
+ * Author: Christopher Strecker
+ * Website: https://github.com/StreckerCM/GeoMagSharpGUI
+ ****************************************************************************/
using System;
namespace GeoMagSharp
{
+ ///
+ /// Static calculator for magnetic field values using spherical harmonic coefficients.
+ /// Based on the NOAA World Magnetic Model (WMM) algorithm.
+ ///
public static class Calculator
{
diff --git a/GeoMagSharp/Enums/GeoMagEnums.cs b/GeoMagSharp/Enums/GeoMagEnums.cs
index abb9ede..a57a8ba 100644
--- a/GeoMagSharp/Enums/GeoMagEnums.cs
+++ b/GeoMagSharp/Enums/GeoMagEnums.cs
@@ -29,7 +29,7 @@ public enum CoordinateSystem
public enum Algorithm
{
///
- /// British Geological Survey algorithm
+ /// Default spherical harmonic algorithm
///
BGS = 1,
diff --git a/GeoMagSharp/ExtensionMethods.cs b/GeoMagSharp/ExtensionMethods.cs
index 4566deb..92bf64c 100644
--- a/GeoMagSharp/ExtensionMethods.cs
+++ b/GeoMagSharp/ExtensionMethods.cs
@@ -11,6 +11,9 @@
namespace GeoMagSharp
{
+ ///
+ /// Extension methods for date/time conversion, angle conversion, and model identification.
+ ///
public static class ExtensionMethods
{
///
@@ -167,11 +170,21 @@ public static DateTime ToDateTime(this double decDate)
return new DateTime(yearInt, monthInt, dayInt);
}
+ ///
+ /// Determines whether the year of the specified date falls within the valid range (1900 to DateTime.MaxValue.Year).
+ ///
+ /// The date to validate.
+ /// true if the year is within the valid range; otherwise, false.
public static bool IsValidYear(this DateTime date)
{
return (1900 <= date.Year && date.Year <= DateTime.MaxValue.Year);
}
+ ///
+ /// Determines whether the specified decimal year falls within the valid range (1900 to max DateTime as decimal).
+ ///
+ /// The decimal year to validate.
+ /// true if the decimal year is within the valid range; otherwise, false.
public static bool IsValidYear(this double decDate)
{
return (1900D <= decDate && decDate <= DateTime.MaxValue.ToDecimal());
diff --git a/GeoMagSharp/GeoMag.cs b/GeoMagSharp/GeoMag.cs
index f6131e2..aaef4e0 100644
--- a/GeoMagSharp/GeoMag.cs
+++ b/GeoMagSharp/GeoMag.cs
@@ -1,231 +1,269 @@
-/****************************************************************************
- * File: GeoMag.cs
- * Description: Routines to provide an interface to the calculation methods
- * Author: Christopher Strecker
- * Website: https://github.com/StreckerCM/GeoMagSharpGUI
- * Warnings:
- * Current version:
- * ****************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-
-
-namespace GeoMagSharp
-{
- public class GeoMag
- {
- public List ResultsOfCalculation;
-
- private MagneticModelSet _Models;
-
- private CalculationOptions _CalculationOptions;
-
- public GeoMag()
- {
- _Models = null;
- }
-
- public void LoadModel(string modelFile)
- {
- _Models = null;
-
- if (string.IsNullOrEmpty(modelFile))
- throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
-
- _Models = ModelReader.Read(modelFile);
-
- }
-
- public void LoadModel(MagneticModelSet modelSet)
- {
- _Models = null;
-
- if (modelSet == null)
- throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
-
- _Models = modelSet;
-
- }
-
- public void LoadModel(string modelFile, string svFile)
- {
- _Models = null;
-
- if (string.IsNullOrEmpty(modelFile))
- throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
-
- _Models = ModelReader.Read(modelFile, svFile);
-
- }
-
- public void MagneticCalculations(CalculationOptions inCalculationOptions)
- {
- _CalculationOptions = null;
- ResultsOfCalculation = null;
-
- if (_Models == null || _Models.NumberOfModels.Equals(0))
- throw new GeoMagExceptionModelNotLoaded("Error: No models avaliable for calculation");
-
- if (!_Models.IsDateInRange(inCalculationOptions.StartDate))
- {
- throw new GeoMagExceptionOutOfRange(string.Format("Error: the date {0} is out of range for this model{1}The valid date range for the is {2} to {3}",
- inCalculationOptions.StartDate.ToShortDateString(), Environment.NewLine, _Models.MinDate.ToDateTime().ToShortDateString(),
- _Models.MaxDate.ToDateTime().ToShortDateString()));
-
- }
-
- if (inCalculationOptions.EndDate.Equals(DateTime.MinValue)) inCalculationOptions.EndDate = inCalculationOptions.StartDate;
-
- if (!_Models.IsDateInRange(inCalculationOptions.EndDate))
- {
- throw new GeoMagExceptionOutOfRange(string.Format("Error: the date {0} is out of range for this model{1}The valid date range for the is {2} to {3}",
- inCalculationOptions.EndDate.ToShortDateString(), Environment.NewLine, _Models.MinDate.ToDateTime().ToShortDateString(),
- _Models.MaxDate.ToDateTime().ToShortDateString()));
- }
-
- TimeSpan timespan = (inCalculationOptions.EndDate.Date - inCalculationOptions.StartDate.Date);
-
- double dayInc = inCalculationOptions.StepInterval < 1 ? 1 : inCalculationOptions.StepInterval;
-
- double dateIdx = 0;
-
- ResultsOfCalculation = new List();
-
- _CalculationOptions = new CalculationOptions(inCalculationOptions);
-
- while (dateIdx <= timespan.Days)
- {
-
- var internalSH = new Coefficients();
-
- var externalSH = new Coefficients();
-
- DateTime intervalDate = _CalculationOptions.StartDate.AddDays(dateIdx);
-
- _Models.GetIntExt(intervalDate.ToDecimal(), out internalSH, out externalSH);
-
- var magCalcDate = Calculator.SpotCalculation(_CalculationOptions, intervalDate, _Models, internalSH, externalSH, _Models.EarthRadius);
-
- if (magCalcDate != null) ResultsOfCalculation.Add(magCalcDate);
-
- dateIdx = ((dateIdx < timespan.Days) && ((dateIdx + dayInc) > timespan.Days))
- ? timespan.Days
- : dateIdx + dayInc;
-
- }
-
- }
-
-
- public void SaveResults(string fileName, bool loadAfterSave = false)
- {
- if (ResultsOfCalculation == null)
- throw new GeoMagExceptionModelNotLoaded("Error: No calculation results to save");
-
- if (ModelReader.IsFileLocked(fileName))
- throw new GeoMagExceptionOpenError(string.Format("Error: The file '{0}' is locked by another user or application",
- Path.GetFileName(fileName)));
-
- if (File.Exists(fileName))
- {
-
- try
- {
- File.Delete(fileName);
- }
- catch (Exception e)
- {
-
- throw new GeoMagExceptionOpenError(string.Format("Error: The file '{0}' could not be deleted: {1}",
- System.IO.Path.GetFileName(fileName), e.ToString()));
- }
-
- }
-
- Int32 lineCount = 0;
-
- //Int32 lineNumColIdx = -1;
-
- var tabStrRight = new StringBuilder();
-
- //Build header
-
-
-
- tabStrRight.AppendFormat("{0}:\t{1}{2}", "Model".PadLeft(15, ' '), Path.GetFileNameWithoutExtension(_Models.Name).ToUpper(), Environment.NewLine);
- lineCount++;
-
- tabStrRight.AppendFormat("{0}:\t{1}{2}", "latitude".PadLeft(15, ' '), _CalculationOptions.Latitude.ToString("F7"), Environment.NewLine);
- lineCount++;
-
- tabStrRight.AppendFormat("{0}:\t{1}{2}", "longitude".PadLeft(15, ' '), _CalculationOptions.Longitude.ToString("F7"), Environment.NewLine);
- lineCount++;
-
- var elevation = _CalculationOptions.GetElevation;
-
- tabStrRight.AppendFormat("{0}:\t{1}\t{2}{3}", string.Format("{0}", elevation[0]).PadLeft(15, ' '), Convert.ToDouble(elevation[1]).ToString("F4"), elevation[2], Environment.NewLine);
- lineCount++;
-
- tabStrRight.AppendFormat("{0}", Environment.NewLine);
- lineCount++;
-
- const Int32 padlen = 25;
-
- const string rowFormat = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}{8}";
-
- //Build Column Header
-
- tabStrRight.AppendFormat(rowFormat,
- "Date".PadRight(padlen, ' '), "Declination (+E/W)".PadRight(padlen, ' '), "Inclination (+D/-U)".PadRight(padlen, ' '),
- "Horizontal Intensity".PadRight(padlen, ' '), "North Comp (+N/-S)".PadRight(padlen, ' '), "East Comp (+E/-W)".PadRight(padlen, ' '),
- "Vertical Comp (+D/-U)".PadRight(padlen, ' '), "Total Field".PadRight(padlen, ' '), Environment.NewLine);
- lineCount++;
-
- tabStrRight.AppendFormat(rowFormat,
- "".PadRight(padlen, ' '), "deg".PadRight(padlen, ' '), "deg".PadRight(padlen, ' '),
- "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '),
- "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '), Environment.NewLine);
- lineCount++;
-
- tabStrRight.AppendFormat("{0}", Environment.NewLine);
- lineCount++;
-
- //Build result rows
-
- foreach(var result in ResultsOfCalculation)
- {
- //Date
- tabStrRight.AppendFormat(rowFormat,
- result.Date.ToString("MM/dd/yyyy").PadRight(padlen, ' '), result.Declination.Value.ToString("F3").PadRight(padlen, ' '),
- result.Inclination.Value.ToString("F3").PadRight(padlen, ' '), result.HorizontalIntensity.Value.ToString("F2").PadRight(padlen, ' '),
- result.NorthComp.Value.ToString("F2").PadRight(padlen, ' '), result.EastComp.Value.ToString("F2").PadRight(padlen, ' '),
- result.VerticalComp.Value.ToString("F2").PadRight(padlen, ' '), result.TotalField.Value.ToString("F2").PadRight(padlen, ' '),
- Environment.NewLine);
-
- lineCount++;
- }
-
- tabStrRight.AppendFormat(rowFormat,
- "Change Per year".PadRight(padlen, ' '), ResultsOfCalculation.First().Declination.ChangePerYear.ToString("F3").PadRight(padlen, ' '),
- ResultsOfCalculation.First().Inclination.ChangePerYear.ToString("F3").PadRight(padlen, ' '), ResultsOfCalculation.First().HorizontalIntensity.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
- ResultsOfCalculation.First().NorthComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '), ResultsOfCalculation.First().EastComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
- ResultsOfCalculation.First().VerticalComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '), ResultsOfCalculation.First().TotalField.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
- Environment.NewLine);
-
- // Write the stream contents to a text fle
- using (StreamWriter outFile = File.AppendText(fileName))
- {
- outFile.Write(tabStrRight.ToString());
- }
-
-
-
-
- }
-
- }
-}
+/****************************************************************************
+ * File: GeoMag.cs
+ * Description: Routines to provide an interface to the calculation methods
+ * Author: Christopher Strecker
+ * Website: https://github.com/StreckerCM/GeoMagSharpGUI
+ ****************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+
+namespace GeoMagSharp
+{
+ ///
+ /// Provides an interface to magnetic field calculation methods.
+ /// Handles model loading, magnetic field computation, and result export.
+ ///
+ public class GeoMag
+ {
+ ///
+ /// The results of the most recent magnetic field calculation.
+ ///
+ public List ResultsOfCalculation;
+
+ private MagneticModelSet _Models;
+
+ private CalculationOptions _CalculationOptions;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public GeoMag()
+ {
+ _Models = null;
+ }
+
+ ///
+ /// Loads a magnetic model from a coefficient file.
+ ///
+ /// Path to the coefficient file (.COF or .DAT format)
+ /// Thrown when is null or empty.
+ public void LoadModel(string modelFile)
+ {
+ _Models = null;
+
+ if (string.IsNullOrEmpty(modelFile))
+ throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
+
+ _Models = ModelReader.Read(modelFile);
+
+ }
+
+ ///
+ /// Loads a magnetic model from a pre-built .
+ ///
+ /// The magnetic model set to use for calculations.
+ /// Thrown when is null.
+ public void LoadModel(MagneticModelSet modelSet)
+ {
+ _Models = null;
+
+ if (modelSet == null)
+ throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
+
+ _Models = modelSet;
+
+ }
+
+ ///
+ /// Loads a magnetic model from separate main field and secular variation coefficient files.
+ ///
+ /// Path to the main field coefficient file.
+ /// Path to the secular variation coefficient file.
+ /// Thrown when is null or empty.
+ public void LoadModel(string modelFile, string svFile)
+ {
+ _Models = null;
+
+ if (string.IsNullOrEmpty(modelFile))
+ throw new GeoMagExceptionFileNotFound("Error coefficient file name not specified");
+
+ _Models = ModelReader.Read(modelFile, svFile);
+
+ }
+
+ ///
+ /// Performs magnetic field calculations over the specified date range and location.
+ /// Results are stored in .
+ ///
+ /// The calculation parameters including location, dates, and elevation.
+ /// Thrown when no model has been loaded.
+ /// Thrown when the start or end date is outside the model's valid range.
+ public void MagneticCalculations(CalculationOptions inCalculationOptions)
+ {
+ _CalculationOptions = null;
+ ResultsOfCalculation = null;
+
+ if (_Models == null || _Models.NumberOfModels.Equals(0))
+ throw new GeoMagExceptionModelNotLoaded("Error: No models avaliable for calculation");
+
+ if (!_Models.IsDateInRange(inCalculationOptions.StartDate))
+ {
+ throw new GeoMagExceptionOutOfRange(string.Format("Error: the date {0} is out of range for this model{1}The valid date range for the is {2} to {3}",
+ inCalculationOptions.StartDate.ToShortDateString(), Environment.NewLine, _Models.MinDate.ToDateTime().ToShortDateString(),
+ _Models.MaxDate.ToDateTime().ToShortDateString()));
+
+ }
+
+ if (inCalculationOptions.EndDate.Equals(DateTime.MinValue)) inCalculationOptions.EndDate = inCalculationOptions.StartDate;
+
+ if (!_Models.IsDateInRange(inCalculationOptions.EndDate))
+ {
+ throw new GeoMagExceptionOutOfRange(string.Format("Error: the date {0} is out of range for this model{1}The valid date range for the is {2} to {3}",
+ inCalculationOptions.EndDate.ToShortDateString(), Environment.NewLine, _Models.MinDate.ToDateTime().ToShortDateString(),
+ _Models.MaxDate.ToDateTime().ToShortDateString()));
+ }
+
+ TimeSpan timespan = (inCalculationOptions.EndDate.Date - inCalculationOptions.StartDate.Date);
+
+ double dayInc = inCalculationOptions.StepInterval < 1 ? 1 : inCalculationOptions.StepInterval;
+
+ double dateIdx = 0;
+
+ ResultsOfCalculation = new List();
+
+ _CalculationOptions = new CalculationOptions(inCalculationOptions);
+
+ while (dateIdx <= timespan.Days)
+ {
+
+ var internalSH = new Coefficients();
+
+ var externalSH = new Coefficients();
+
+ DateTime intervalDate = _CalculationOptions.StartDate.AddDays(dateIdx);
+
+ _Models.GetIntExt(intervalDate.ToDecimal(), out internalSH, out externalSH);
+
+ var magCalcDate = Calculator.SpotCalculation(_CalculationOptions, intervalDate, _Models, internalSH, externalSH, _Models.EarthRadius);
+
+ if (magCalcDate != null) ResultsOfCalculation.Add(magCalcDate);
+
+ dateIdx = ((dateIdx < timespan.Days) && ((dateIdx + dayInc) > timespan.Days))
+ ? timespan.Days
+ : dateIdx + dayInc;
+
+ }
+
+ }
+
+
+ ///
+ /// Saves the calculation results to a tab-separated text file.
+ ///
+ /// The output file path.
+ /// Reserved for future use.
+ /// Thrown when no calculation results are available.
+ /// Thrown when the file is locked or cannot be deleted.
+ public void SaveResults(string fileName, bool loadAfterSave = false)
+ {
+ if (ResultsOfCalculation == null)
+ throw new GeoMagExceptionModelNotLoaded("Error: No calculation results to save");
+
+ if (ModelReader.IsFileLocked(fileName))
+ throw new GeoMagExceptionOpenError(string.Format("Error: The file '{0}' is locked by another user or application",
+ Path.GetFileName(fileName)));
+
+ if (File.Exists(fileName))
+ {
+
+ try
+ {
+ File.Delete(fileName);
+ }
+ catch (Exception e)
+ {
+
+ throw new GeoMagExceptionOpenError(string.Format("Error: The file '{0}' could not be deleted: {1}",
+ System.IO.Path.GetFileName(fileName), e.ToString()));
+ }
+
+ }
+
+ Int32 lineCount = 0;
+
+ //Int32 lineNumColIdx = -1;
+
+ var tabStrRight = new StringBuilder();
+
+ //Build header
+
+
+
+ tabStrRight.AppendFormat("{0}:\t{1}{2}", "Model".PadLeft(15, ' '), Path.GetFileNameWithoutExtension(_Models.Name).ToUpper(), Environment.NewLine);
+ lineCount++;
+
+ tabStrRight.AppendFormat("{0}:\t{1}{2}", "latitude".PadLeft(15, ' '), _CalculationOptions.Latitude.ToString("F7"), Environment.NewLine);
+ lineCount++;
+
+ tabStrRight.AppendFormat("{0}:\t{1}{2}", "longitude".PadLeft(15, ' '), _CalculationOptions.Longitude.ToString("F7"), Environment.NewLine);
+ lineCount++;
+
+ var elevation = _CalculationOptions.GetElevation;
+
+ tabStrRight.AppendFormat("{0}:\t{1}\t{2}{3}", string.Format("{0}", elevation[0]).PadLeft(15, ' '), Convert.ToDouble(elevation[1]).ToString("F4"), elevation[2], Environment.NewLine);
+ lineCount++;
+
+ tabStrRight.AppendFormat("{0}", Environment.NewLine);
+ lineCount++;
+
+ const Int32 padlen = 25;
+
+ const string rowFormat = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}{8}";
+
+ //Build Column Header
+
+ tabStrRight.AppendFormat(rowFormat,
+ "Date".PadRight(padlen, ' '), "Declination (+E/W)".PadRight(padlen, ' '), "Inclination (+D/-U)".PadRight(padlen, ' '),
+ "Horizontal Intensity".PadRight(padlen, ' '), "North Comp (+N/-S)".PadRight(padlen, ' '), "East Comp (+E/-W)".PadRight(padlen, ' '),
+ "Vertical Comp (+D/-U)".PadRight(padlen, ' '), "Total Field".PadRight(padlen, ' '), Environment.NewLine);
+ lineCount++;
+
+ tabStrRight.AppendFormat(rowFormat,
+ "".PadRight(padlen, ' '), "deg".PadRight(padlen, ' '), "deg".PadRight(padlen, ' '),
+ "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '),
+ "nT".PadRight(padlen, ' '), "nT".PadRight(padlen, ' '), Environment.NewLine);
+ lineCount++;
+
+ tabStrRight.AppendFormat("{0}", Environment.NewLine);
+ lineCount++;
+
+ //Build result rows
+
+ foreach(var result in ResultsOfCalculation)
+ {
+ //Date
+ tabStrRight.AppendFormat(rowFormat,
+ result.Date.ToString("MM/dd/yyyy").PadRight(padlen, ' '), result.Declination.Value.ToString("F3").PadRight(padlen, ' '),
+ result.Inclination.Value.ToString("F3").PadRight(padlen, ' '), result.HorizontalIntensity.Value.ToString("F2").PadRight(padlen, ' '),
+ result.NorthComp.Value.ToString("F2").PadRight(padlen, ' '), result.EastComp.Value.ToString("F2").PadRight(padlen, ' '),
+ result.VerticalComp.Value.ToString("F2").PadRight(padlen, ' '), result.TotalField.Value.ToString("F2").PadRight(padlen, ' '),
+ Environment.NewLine);
+
+ lineCount++;
+ }
+
+ tabStrRight.AppendFormat(rowFormat,
+ "Change Per year".PadRight(padlen, ' '), ResultsOfCalculation.First().Declination.ChangePerYear.ToString("F3").PadRight(padlen, ' '),
+ ResultsOfCalculation.First().Inclination.ChangePerYear.ToString("F3").PadRight(padlen, ' '), ResultsOfCalculation.First().HorizontalIntensity.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
+ ResultsOfCalculation.First().NorthComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '), ResultsOfCalculation.First().EastComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
+ ResultsOfCalculation.First().VerticalComp.ChangePerYear.ToString("F2").PadRight(padlen, ' '), ResultsOfCalculation.First().TotalField.ChangePerYear.ToString("F2").PadRight(padlen, ' '),
+ Environment.NewLine);
+
+ // Write the stream contents to a text fle
+ using (StreamWriter outFile = File.AppendText(fileName))
+ {
+ outFile.Write(tabStrRight.ToString());
+ }
+
+
+
+
+ }
+
+ }
+}
diff --git a/GeoMagSharp/GeoMagException.cs b/GeoMagSharp/GeoMagException.cs
index d9d12dd..2d43f4d 100644
--- a/GeoMagSharp/GeoMagException.cs
+++ b/GeoMagSharp/GeoMagException.cs
@@ -48,9 +48,9 @@ protected GeoMagException(
}
}
- ///
- /// Thrown when file is not found
- ///
+ ///
+ /// Thrown when a magnetic model has not been loaded before performing calculations.
+ ///
[Serializable]
public class GeoMagExceptionModelNotLoaded : GeoMagException
{
@@ -75,9 +75,9 @@ public GeoMagExceptionModelNotLoaded(SerializationInfo info, StreamingContext co
}
- ///
- /// Thrown when file is not found
- ///
+ ///
+ /// Thrown when a coefficient file cannot be found at the specified path.
+ ///
[Serializable]
public class GeoMagExceptionFileNotFound : GeoMagException
{
@@ -101,9 +101,9 @@ public GeoMagExceptionFileNotFound(SerializationInfo info, StreamingContext cont
}
}
- ///
- /// Thrown when file has an invalid charater in a line
- ///
+ ///
+ /// Thrown when a coefficient file contains an invalid character in a data line.
+ ///
[Serializable]
public class GeoMagExceptionBadCharacter : GeoMagException
{
@@ -128,9 +128,9 @@ public GeoMagExceptionBadCharacter(SerializationInfo info, StreamingContext cont
}
- ///
- /// Thrown when file has an invalid number of coefficients
- ///
+ ///
+ /// Thrown when a coefficient file contains an unexpected number of coefficients.
+ ///
[Serializable]
public class GeoMagExceptionBadNumberOfCoefficients : GeoMagException
{
@@ -154,9 +154,9 @@ public GeoMagExceptionBadNumberOfCoefficients(SerializationInfo info, StreamingC
}
}
- ///
- /// Thrown when file has an invalid number of coefficients
- ///
+ ///
+ /// Thrown when a coefficient file cannot be opened or read.
+ ///
[Serializable]
public class GeoMagExceptionOpenError : GeoMagException
{
@@ -180,9 +180,9 @@ public GeoMagExceptionOpenError(SerializationInfo info, StreamingContext context
}
}
- ///
- /// Thrown when file has an invalid number of coefficients
- ///
+ ///
+ /// Thrown when a calculation date or parameter is outside the valid range.
+ ///
[Serializable]
public class GeoMagExceptionOutOfRange : GeoMagException
{
@@ -206,9 +206,9 @@ public GeoMagExceptionOutOfRange(SerializationInfo info, StreamingContext contex
}
}
- ///
- /// Thrown when file has an invalid number of coefficients
- ///
+ ///
+ /// Thrown when a calculation or model loading operation exceeds available memory.
+ ///
[Serializable]
public class GeoMagExceptionOutOfMemory : GeoMagException
{
diff --git a/GeoMagSharp/ModelReader.cs b/GeoMagSharp/ModelReader.cs
index cadcd85..4db164c 100644
--- a/GeoMagSharp/ModelReader.cs
+++ b/GeoMagSharp/ModelReader.cs
@@ -1,12 +1,10 @@
/****************************************************************************
* File: ModelReader.cs
- * Description: Routines read a given model file into the model structure
- * to be used for calculation
- * Author: Christopher Strecker
- * Website: https://github.com/StreckerCM/GeoMagSharpGUI
- * Warnings:
- * Current version:
- * ****************************************************************************/
+ * Description: Routines to read magnetic model coefficient files into
+ * the model structure for calculation
+ * Author: Christopher Strecker
+ * Website: https://github.com/StreckerCM/GeoMagSharpGUI
+ ****************************************************************************/
using System;
using System.Globalization;
@@ -15,6 +13,9 @@
namespace GeoMagSharp
{
+ ///
+ /// Reads and parses magnetic model coefficient files (COF/DAT) into model structures.
+ ///
public static class ModelReader
{
///
diff --git a/GeoMagSharp/Models/Configuration/CalculationOptions.cs b/GeoMagSharp/Models/Configuration/CalculationOptions.cs
index f28622c..30c254d 100644
--- a/GeoMagSharp/Models/Configuration/CalculationOptions.cs
+++ b/GeoMagSharp/Models/Configuration/CalculationOptions.cs
@@ -17,6 +17,9 @@ public class CalculationOptions
{
#region Constructors
+ ///
+ /// Initializes a new instance with default values (origin point, current date, default algorithm).
+ ///
public CalculationOptions()
{
Latitude = 0;
@@ -32,6 +35,10 @@ public CalculationOptions()
ElevationIsAltitude = true;
}
+ ///
+ /// Initializes a new instance by copying values from another .
+ ///
+ /// The source options to copy from.
public CalculationOptions(CalculationOptions other)
{
Latitude = other.Latitude;
@@ -49,16 +56,35 @@ public CalculationOptions(CalculationOptions other)
#endregion
+ /// Geographic latitude in decimal degrees (-90 to +90).
public double Latitude { get; set; }
+
+ /// Geographic longitude in decimal degrees (-180 to +180).
public double Longitude { get; set; }
+
+ /// Start date for the calculation range.
public DateTime StartDate { get; set; }
+
+ /// End date for the calculation range. If equal to , defaults to .
public DateTime EndDate { get; set; }
+
+ /// Step interval in days between calculations in a date range.
public double StepInterval { get; set; }
+
+ /// Whether to calculate secular variation (annual rate of change).
public bool SecularVariation { get; set; }
+
+ /// The calculation algorithm to use.
public Algorithm CalculationMethod { get; set; }
#region Getters & Setters
+ ///
+ /// Sets the elevation value, unit, and type (altitude or depth).
+ ///
+ /// The elevation value.
+ /// The unit of measurement.
+ /// true for altitude above sea level; false for depth below sea level.
public void SetElevation(double value, Distance.Unit unit, bool isAltitude = true)
{
ElevationValue = value;
@@ -66,6 +92,9 @@ public void SetElevation(double value, Distance.Unit unit, bool isAltitude = tru
ElevationIsAltitude = isAltitude;
}
+ ///
+ /// Gets the elevation converted to depth in meters. Positive for depth, negative for altitude.
+ ///
public double DepthInM
{
get
@@ -93,6 +122,9 @@ public double DepthInM
}
}
+ ///
+ /// Gets the elevation converted to altitude in kilometers. Positive for altitude, negative for depth.
+ ///
public double AltitudeInKm
{
get
@@ -120,6 +152,9 @@ public double AltitudeInKm
}
}
+ ///
+ /// Gets the elevation as a list of [label, value, unit abbreviation] for display purposes.
+ ///
public List
public class MagneticModelCollection : IEnumerable
{
+ /// The internal list of magnetic model sets.
[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
public List TList { get; private set; }
#region Constructors
+ ///
+ /// Initializes a new instance with an empty model list.
+ ///
public MagneticModelCollection()
{
TList = new List();
@@ -33,21 +37,39 @@ public MagneticModelCollection()
#region Base Class Methods
+ ///
+ /// Adds a model set to the collection.
+ ///
+ /// The model set to add.
public void Add(MagneticModelSet item)
{
TList.Add(item);
}
+ ///
+ /// Adds a range of model sets to the collection.
+ ///
+ /// The model sets to add.
public void AddRange(IEnumerable collection)
{
TList.AddRange(collection);
}
+ ///
+ /// Searches for a model set that matches the specified predicate.
+ ///
+ /// The predicate to match against.
+ /// The first matching model set, or null if not found.
public MagneticModelSet Find(Predicate match)
{
return TList.Find(match);
}
+ ///
+ /// Searches for all model sets that match the specified predicate.
+ ///
+ /// The predicate to match against.
+ /// A list of all matching model sets.
public List FindAll(Predicate match)
{
return TList.FindAll(match);
@@ -97,6 +119,10 @@ public bool AddOrReplace(MagneticModelSet item)
return false;
}
+ ///
+ /// Returns an enumerator that iterates through the model sets.
+ ///
+ /// An enumerator for the collection.
public IEnumerator GetEnumerator()
{
return TList.GetEnumerator();
@@ -111,6 +137,11 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
#region Object Serializers
+ ///
+ /// Serializes the collection to a JSON file.
+ ///
+ /// The file path to save to.
+ /// true if the save was successful; otherwise, false.
public bool Save(string filename)
{
if (string.IsNullOrEmpty(filename)) return false;
@@ -144,6 +175,11 @@ public bool Save(string filename)
return wasSucessful;
}
+ ///
+ /// Deserializes a collection from a JSON file.
+ ///
+ /// The file path to load from.
+ /// The loaded collection, or a new empty collection if the file is missing or invalid.
public static MagneticModelCollection Load(string filename)
{
if (string.IsNullOrEmpty(filename)) return new MagneticModelCollection();
@@ -182,6 +218,10 @@ public static MagneticModelCollection Load(string filename)
#region getters & setters
+ ///
+ /// Gets a DataTable representation of all models for UI data binding.
+ /// Columns: ID, ModelName, FileNames, DateMin, DateMax, NumberOfModels, Type.
+ ///
public DataTable GetDataTable
{
get
diff --git a/GeoMagSharp/Models/Magnetic/MagneticModelSet.cs b/GeoMagSharp/Models/Magnetic/MagneticModelSet.cs
index 8f0131f..ffac2e4 100644
--- a/GeoMagSharp/Models/Magnetic/MagneticModelSet.cs
+++ b/GeoMagSharp/Models/Magnetic/MagneticModelSet.cs
@@ -20,11 +20,18 @@ public class MagneticModelSet
{
#region Constructors
+ ///
+ /// Initializes a new instance with an empty model list.
+ ///
public MagneticModelSet()
{
Models = new List();
}
+ ///
+ /// Initializes a new instance by copying values from another .
+ ///
+ /// The source model set to copy.
public MagneticModelSet(MagneticModelSet other)
{
ID = other.ID;
@@ -44,6 +51,10 @@ public MagneticModelSet(MagneticModelSet other)
#region Public Methods
+ ///
+ /// Adds a magnetic model and updates the date range to include the model's epoch.
+ ///
+ /// The magnetic model to add.
public void AddModel(MagneticModel newModel)
{
if (newModel == null) return;
@@ -57,6 +68,11 @@ public void AddModel(MagneticModel newModel)
MaxDate = newModel.Year;
}
+ ///
+ /// Adds a spherical harmonic coefficient to the model at the specified index.
+ ///
+ /// The index of the model to add the coefficient to.
+ /// The coefficient value.
public void AddCoefficients(Int32 modelIdx, double coeff)
{
if (modelIdx.Equals(-1)) return;
@@ -290,6 +306,7 @@ subtract what is needed at start and end of time span
#region getters & setters
+ /// Unique identifier for this model set.
public Guid ID
{
get
@@ -304,6 +321,7 @@ public Guid ID
}
}
+ /// Display name of the model (e.g., "WMM2025").
public string Name
{
get
@@ -318,6 +336,7 @@ public string Name
}
}
+ /// List of coefficient file paths used to build this model set.
public List FileNames
{
get
@@ -332,6 +351,7 @@ public List FileNames
}
}
+ /// The known model type (WMM, IGRF, EMM, etc.).
public knownModels Type
{
get
@@ -346,6 +366,7 @@ public knownModels Type
}
}
+ /// Minimum valid date (decimal year) for this model set. Only accepts values earlier than the current minimum.
public double MinDate
{
get
@@ -362,6 +383,7 @@ public double MinDate
}
}
+ /// Maximum valid date (decimal year) for this model set. Only accepts values later than the current maximum.
public double MaxDate
{
get
@@ -378,6 +400,7 @@ public double MaxDate
}
}
+ /// Earth's radius in kilometers used by this model.
public double EarthRadius
{
get
@@ -392,6 +415,7 @@ public double EarthRadius
}
}
+ /// Gets a copy of the internal models list.
[JsonIgnore]
public List GetModels
{
@@ -401,6 +425,7 @@ public List GetModels
}
}
+ /// Gets the number of models in the set, or -1 if models are null.
[JsonIgnore]
public Int32 NumberOfModels
{
diff --git a/GeoMagSharp/Models/Results/GeoMagVector.cs b/GeoMagSharp/Models/Results/GeoMagVector.cs
index ff46387..61a0edb 100644
--- a/GeoMagSharp/Models/Results/GeoMagVector.cs
+++ b/GeoMagSharp/Models/Results/GeoMagVector.cs
@@ -14,6 +14,9 @@ public class GeoMagVector
{
#region Constructors
+ ///
+ /// Initializes a new instance with all components set to zero.
+ ///
public GeoMagVector()
{
d = 0;
@@ -25,6 +28,10 @@ public GeoMagVector()
f = 0;
}
+ ///
+ /// Initializes a new instance by copying all components from another .
+ ///
+ /// The source vector to copy.
public GeoMagVector(GeoMagVector other)
{
d = other.d;
diff --git a/GeoMagSharp/Models/Results/MagneticCalculations.cs b/GeoMagSharp/Models/Results/MagneticCalculations.cs
index 592e8a7..aa5eac5 100644
--- a/GeoMagSharp/Models/Results/MagneticCalculations.cs
+++ b/GeoMagSharp/Models/Results/MagneticCalculations.cs
@@ -16,6 +16,9 @@ public class MagneticCalculations
{
#region Constructors
+ ///
+ /// Initializes a new instance with the current date and zero-valued components.
+ ///
public MagneticCalculations()
{
Date = DateTime.Now;
@@ -28,6 +31,10 @@ public MagneticCalculations()
TotalField = new MagneticValue();
}
+ ///
+ /// Initializes a new instance by copying values from another .
+ ///
+ /// The source calculation results to copy.
public MagneticCalculations(MagneticCalculations other)
{
Date = other.Date;
@@ -40,6 +47,12 @@ public MagneticCalculations(MagneticCalculations other)
TotalField = new MagneticValue(other.TotalField);
}
+ ///
+ /// Initializes a new instance from field and secular variation vectors.
+ ///
+ /// The date of the calculation.
+ /// The main magnetic field vector.
+ /// The secular variation vector, or null if not computed.
public MagneticCalculations(DateTime inDate, GeoMagVector fieldCalculations, GeoMagVector SecVarCalculations = null)
{
Date = inDate;
diff --git a/GeoMagSharp/Models/Results/MagneticValue.cs b/GeoMagSharp/Models/Results/MagneticValue.cs
index 76934b2..c5267d1 100644
--- a/GeoMagSharp/Models/Results/MagneticValue.cs
+++ b/GeoMagSharp/Models/Results/MagneticValue.cs
@@ -14,12 +14,19 @@ public class MagneticValue
{
#region Constructors
+ ///
+ /// Initializes a new instance with zero value and zero change per year.
+ ///
public MagneticValue()
{
Value = 0.0;
ChangePerYear = 0.0;
}
+ ///
+ /// Initializes a new instance by copying values from another .
+ ///
+ /// The source value to copy.
public MagneticValue(MagneticValue other)
{
Value = other.Value;
diff --git a/GeoMagSharp/Units.cs b/GeoMagSharp/Units.cs
index 99e97b7..23ba0d9 100644
--- a/GeoMagSharp/Units.cs
+++ b/GeoMagSharp/Units.cs
@@ -13,17 +13,33 @@
namespace GeoMagSharp
{
+ ///
+ /// Provides distance and angle unit types with conversion between string and enum representations.
+ ///
public static class Distance
{
+ ///
+ /// Distance measurement units.
+ ///
public enum Unit
{
+ /// Unknown or unspecified unit.
unknown = 0,
+ /// Meters.
meter = 1,
+ /// Kilometers.
kilometer = 2,
+ /// Feet.
foot = 3,
+ /// Miles.
mile = 4
}
+ ///
+ /// Converts a enum value to its abbreviation string.
+ ///
+ /// The distance unit to convert.
+ /// The unit abbreviation (e.g., "m", "ft", "mi"), or empty string for unknown.
public static string ToString(Unit inUnit)
{
switch (inUnit)
@@ -32,7 +48,7 @@ public static string ToString(Unit inUnit)
return @"m";
case Distance.Unit.kilometer:
- return @"mi";
+ return @"km";
case Distance.Unit.foot:
return @"ft";
@@ -45,6 +61,11 @@ public static string ToString(Unit inUnit)
return string.Empty;
}
+ ///
+ /// Parses a string to the corresponding enum value.
+ ///
+ /// The unit string (e.g., "m", "km", "ft", "meter").
+ /// The matching , or if not recognized.
public static Unit FromString(string unitString)
{
switch (unitString.ToLower())
@@ -73,15 +94,29 @@ public static Unit FromString(string unitString)
return Distance.Unit.unknown;
}
+ ///
+ /// Provides angle unit types with conversion between string and enum representations.
+ ///
public static class Angle
{
+ ///
+ /// Angle measurement units.
+ ///
public enum Unit
{
+ /// Unknown or unspecified unit.
unknown = 0,
+ /// Degrees.
Degree = 1,
+ /// Radians.
Radian = 2
}
+ ///
+ /// Converts an enum value to its symbol string.
+ ///
+ /// The angle unit to convert.
+ /// The unit symbol (e.g., "°", "g"), or empty string for unknown.
public static string ToString(Unit inUnit)
{
switch (inUnit)
@@ -97,6 +132,11 @@ public static string ToString(Unit inUnit)
return string.Empty;
}
+ ///
+ /// Parses a string to the corresponding enum value.
+ ///
+ /// The unit string (e.g., "degree", "deg", "°", "radian").
+ /// The matching , or if not recognized.
public static Unit FromString(string unitString)
{
switch (unitString.ToLower())
diff --git a/README.md b/README.md
index fa29d5a..02c1f2a 100644
--- a/README.md
+++ b/README.md
@@ -138,6 +138,5 @@ See [GeoMagGUI/documentation/LICENSE](./GeoMagGUI/documentation/LICENSE)
## Credits
-- Original NOAA Geomag 7.0 software
-- British Geological Survey (BGS) calculation algorithms
+- NOAA World Magnetic Model (WMM) and Geomag 7.0 software
- Port to C# with GUI by StreckerCM