using System; using System.Data; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using log4net; namespace DeltaShell.Plugins.XBeach.Api { public class XBeachApi : IXBeachApi { private static readonly ILog log = LogManager.GetLogger(typeof(XBeachApi)); private string currentDirectory; bool isDisposed; private bool isInitialized; public XBeachApi() { //var del = new XBeachDll.MyDelegate(OnLogMessangeThrown); //XBeachDll.assignlogdelegate(del); } private void OnLogMessangeThrown(int code, string message) { if (NewLogMessage != null) { NewLogMessage(this,new EventArgs()); } } public void Initialize(string workingDirectory) { if(isInitialized) { throw new NotSupportedException("XBeach is already initialized, use remoting if you need to use multiple instances"); } currentDirectory = Directory.GetCurrentDirectory(); Directory.SetCurrentDirectory(workingDirectory); XBeachDll.init(); grid = null; isInitialized = true; } public event EventHandler NewLogMessage; private CurvilinearGrid grid; public CurvilinearGrid Grid { get { Trace.Assert(isInitialized, "XBeach model should be initialized"); if (grid != null) { return grid; } grid = new CurvilinearGrid(); // Get the size of the grid XBeachDll.getparameter("nx", ref grid.SizeM); XBeachDll.getparameter("ny", ref grid.SizeN); grid.SizeN++; grid.SizeM++; int size = grid.SizeN * grid.SizeM; grid.X = new double[size]; grid.Y = new double[size]; IntPtr cptr; cptr = new IntPtr(); XBeachDll.get2ddoublearray("x", ref cptr); Marshal.Copy(cptr, grid.X, 0, size); cptr = new IntPtr(); XBeachDll.get2ddoublearray("y", ref cptr); Marshal.Copy(cptr, grid.Y, 0, size); return grid; } set { if (grid.SizeM != value.SizeM) { throw new ConstraintException("Grid m size doesn't match."); } if (grid.SizeN != value.SizeN) { throw new ConstraintException("Grid n size doesn't match."); } if (value.X.Length != value.Y.Length) { throw new ConstraintException("Grid X and Y should be of equal length"); } // Set the new coordinates in XBeach.... int size = value.X.Length * sizeof(double); // Allocate memory IntPtr xcptr = Marshal.AllocHGlobal(size); // Copy data to the pointer Marshal.Copy(value.X, 0, xcptr, value.X.Length); // Send over data to xbeach. XBeachDll.set2ddoublearray("x", ref xcptr, 1); // Allocate memory (in a separate pointer (to be sure)... IntPtr ycptr = Marshal.AllocHGlobal(size); // Copy data to the pointer Marshal.Copy(value.Y, 0, ycptr, value.Y.Length); // Send over data to xbeach. XBeachDll.set2ddoublearray("y", ref ycptr, 1); grid = value; } } public double[] Get1DDoubleOutputArray(string name) { Trace.Assert(isInitialized, "XBeach model should be initialized"); var outputArray = new double[Grid.Length +1]; if (XBeachDll.get1ddoublearray(name, ref outputArray) == -1) { throw new ArgumentException(String.Format("Parameter \"{0}\" not found", name)); } return outputArray; } public double[] GetDoubleOutputArray(string name) { Trace.Assert(isInitialized, "XBeach model should be initialized"); var outputArray = new double[Grid.Length]; var cptr = new IntPtr(); int status = XBeachDll.get2ddoublearray(name, ref cptr); if (status == -1) { throw new ArgumentException(String.Format("Parameter \"{0}\" not found", name)); } Marshal.Copy(cptr, outputArray, 0, outputArray.GetLength(0)); return outputArray; } public void SetDoubleOutputArray(double[] array, string name) { Trace.Assert(isInitialized, "XBeach model should be initialized"); int size = array.Length * sizeof(double); IntPtr cptr = Marshal.AllocHGlobal(size); Marshal.Copy(array, 0, cptr, array.Length); XBeachDll.set2ddoublearray(name, ref cptr); } public double[] Bathymetry { get { return GetDoubleOutputArray("zb"); } set { Trace.Assert(isInitialized, "XBeach model should be initialized"); int size = value.Length*sizeof (double); IntPtr cptr = Marshal.AllocHGlobal(size); Marshal.Copy(value, 0, cptr, value.Length); XBeachDll.set2ddoublearray("zb", ref cptr); if (CurrentTime == StartTime) { XBeachDll.set2ddoublearray("zb0", ref cptr); XBeachDll.set2ddoublearray("z0bed", ref cptr); } } } public DateTime StartTime { get { // TODO: get from model (tunits) return new DateTime(1970, 1, 1); // by default set StartTime to: 1970-01-01 00:00:00 +0:00 (UNIX epoch) } } public DateTime CurrentTime { get { double time = GetDoubleParameter("t"); if(double.IsNaN(time)) { time = GetDoubleParameter("tstop"); } return StartTime.AddSeconds(time * GetDoubleParameter("morfac")); } } public DateTime StopTime { get { return StartTime.AddSeconds(GetDoubleParameter("tstop") * GetDoubleParameter("morfac")); } } public TimeSpan OutputTimeStep { get { return new TimeSpan(0, 0, 0, (int) (GetDoubleParameter("tint") * GetDoubleParameter("morfac"))); } } public void WriteOutput() { XBeachDll.outputext(); } public string[] GetParameterNames() { return new[] {"tstart", "morstart", "morfac", "morphology", "tstop", "k", "D50", "gw0", "aquiferbot"}; } public Type GetParameterType(string name) { return typeof (double); } public double GetDoubleParameter(string name) { Trace.Assert(isInitialized, "XBeach model should be initialized"); double doublevalue = -1; XBeachDll.getparameter(name, ref doublevalue); return doublevalue; } public int GetIntParameter(string name) { Trace.Assert(isInitialized, "XBeach model should be initialized"); int intvalue = -1; XBeachDll.getparameter(name, ref intvalue); return intvalue; } public void ExecuteStep() { Trace.Assert(isInitialized, "XBeach model should be initialized"); XBeachDll.executestep(); } public void Dispose() { if (!isInitialized) { return; } if (!isDisposed) { XBeachDll.finalize(); Directory.SetCurrentDirectory(currentDirectory); isDisposed = true; } } ~XBeachApi() { if(!isDisposed) { log.Debug("Dispose() was not called explicitly"); Dispose(); } } } }