internal static void setup(IKernelLink ml) { lock (stdLinkLock) { object key = Thread.CurrentThread; Stack s = (Stack)stdLinkHash[key]; if (s == null) { // One-time only operation for any given thread. s = new Stack(); stdLinkHash.Add(key, s); } s.Push(ml); } }
private static ArrayList ReadListOfItemsAsType(string type, IKernelLink link) { int length = link.CheckFunction("List"); ArrayList res = new ArrayList(length); for (int i = 0; i < length; i++) { switch (type) { case "Text": { res.Add(link.GetString()); break; } case "Integer": { res.Add(link.GetInteger()); break; } case "Number": { res.Add(link.GetDouble()); break; } case "Boolean": { res.Add(link.GetBoolean()); break; } case "Any": { object obj = ReadAsAny(link); res.Add(obj); break; } case "Expr": { res.Add(new ExprType(link.GetExpr())); break; } } } return(res); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { string code = null; LinkType linkType = null; // Use the DA object to retrieve the data inside the first input parameter. // If the retieval fails (for example if there is no data) we need to abort. if (!DA.GetData(0, ref code)) { return; } // Link arg is optional. DA.GetData(1, ref linkType); // If the retrieved data is Nothing, we need to abort. if (code == null) { return; } IKernelLink ml = linkType != null ? linkType.Value : Utils.GetLink(); ml.PutFunction("EvaluatePacket", 1); ml.PutFunction("ToExpression", 1); ml.Put(code); ml.EndPacket(); try { ml.WaitForAnswer(); } catch (MathLinkException) { ml.ClearError(); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Error on the link."); ml.NewPacket(); return; } // This is the (likely) temporary feature that puts the Expr result on the second output. Expr debuggingExpr = ml.PeekExpr(); DA.SetData(1, new ExprType(debuggingExpr)); if (!Utils.ReadAndStoreResult("Any", 0, ml, DA, GH_ParamAccess.item, this)) { return; } // 2 is the index here because 1 was used (temporarily) for the debugging feature above. DA.SetData(2, new LinkType(ml)); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { IGH_Goo head = null; LinkType linkType = null; if (!DA.GetData(0, ref head)) { return; } // Link arg is optional. DA.GetData(1, ref linkType); // If the retrieved data is Nothing, we need to abort. if (head == null) { return; } IKernelLink ml = linkType != null ? linkType.Value : Utils.GetLink(); ml.PutFunction("EvaluatePacket", 1); ml.PutNext(ExpressionType.Function); ml.PutArgCount(0); Utils.SendInputParam(head, ml, GH_ParamAccess.item, true); ml.EndPacket(); try { ml.WaitForAnswer(); } catch (MathLinkException) { ml.ClearError(); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Error on the link."); ml.NewPacket(); return; } // This is the (likely) temporary feature that puts the Expr result on the second output. Expr debuggingExpr = ml.PeekExpr(); DA.SetData(1, new ExprType(debuggingExpr)); if (!Utils.ReadAndStoreResult("Any", 0, ml, DA, GH_ParamAccess.item, this)) { return; } DA.SetData(2, new LinkType(ml)); }
public static void SendInputParam(object arg, IKernelLink link, GH_ParamAccess accessType, bool isFunctionHead) { // ScriptVariable() is the method that extracts the wrapped Rhino object from the GH_Goo wrapper. e.g., GH_Text --> string, // or GH_Circle to Rhino.Geometry.Circle. if (accessType == GH_ParamAccess.list) { List <IGH_Goo> list = (List <IGH_Goo>)arg; link.PutFunction("List", list.Count); foreach (IGH_Goo obj in list) { object o = obj.ScriptVariable(); link.Put(o); } } else if (accessType == GH_ParamAccess.tree) { // TODO: Is this right? Do I need to worry about Invalid paths? Should I do this on a loopback link? GH_Structure <IGH_Goo> structure = (GH_Structure <IGH_Goo>)arg; IList <List <IGH_Goo> > data = structure.Branches; link.PutFunction("List", data.Count); foreach (List <IGH_Goo> row in data) { link.PutFunction("List", row.Count); foreach (IGH_Goo obj in row) { object o = obj.ScriptVariable(); link.Put(o); } } } else { object native = (arg is IGH_Goo) ? ((IGH_Goo)arg).ScriptVariable() : arg; // isFunctionHead lets us treat strings as symbols or pure functions for the head (but not used for args). // Need a better way to differentiate strings and symbols. Perhaps a WolframSymbol component that takes a string and emits a symbol. if (isFunctionHead && (native is string || native is Expr && ((Expr)native).StringQ())) { link.PutFunction("ToExpression", 1); link.Put(native); } else { link.Put(native); } } }
/// <summary> /// Starts the Reader thread. /// </summary> /// <param name="link">The link to wait for input on.</param> /// <param name="dieWhenLinkEnds">Whether to exit the thread when the link dies.</param> /// <returns>The Reader thread object.</returns> /// public static Thread StartReader(IKernelLink link, bool dieWhenLinkEnds) { ml = link; quitWhenLinkEnds = dieWhenLinkEnds; linkHasDied = false; StdLink.Link = ml; StdLink.HasReader = true; ml.MessageArrived += new MessageHandler(terminateMsgHandler); readerThread = new Thread(new ThreadStart(Run)); readerThread.Name = ".NET/Link Reader"; readerThread.ApartmentState = ApartmentState.STA; readerThread.Start(); return(readerThread); }
public static void Main(String[] args) { String[] mathArgs = { @"-linkname", @"C:\Program Files\Wolfram Research\Mathematica\11.0\MathKernel.exe -mathlink" }; Console.WriteLine(mathArgs.ToString()); // This launches the Mathematica kernel: IKernelLink ml = MathLinkFactory.CreateKernelLink(mathArgs); // Discard the initial InputNamePacket the kernel will send when launched. ml.WaitAndDiscardAnswer(); // Now compute 2+2 in several different ways. // The easiest way. Send the computation as a string and get the result in a single call: string result = ml.EvaluateToOutputForm("2+2", 0); Console.WriteLine("2 + 2 = " + result); // Use Evaluate() instead of EvaluateToXXX() if you want to read the result as a native type // instead of a string. ml.Evaluate("2+2"); ml.WaitForAnswer(); int intResult = ml.GetInteger(); Console.WriteLine("2 + 2 = " + intResult); // You can also get down to the metal by using methods from IMathLink: ml.PutFunction("EvaluatePacket", 1); ml.PutFunction("Plus", 2); ml.Put(2); ml.Put(2); ml.EndPacket(); ml.WaitForAnswer(); intResult = ml.GetInteger(); Console.WriteLine("2 + 2 = " + intResult); // Always Close link when done: ml.Close(); // Wait for user to close window. Console.WriteLine("Press Return to exit..."); Console.Read(); }
public void Initialize() { mathematicaLink = MathLinkFactory. CreateKernelLink(); mathematicaLink.WaitAndDiscardAnswer(); var netPath = Path.Combine( TemporaryPath, "InstrumentRecognizer", "net.wlnet"); if (!File.Exists(netPath)) { Directory.CreateDirectory(Path.GetDirectoryName(netPath)); File.Copy("net.wlnet", netPath, true); } mathematicaLink.Evaluate($"net = Import[\"{netPath.Replace('\\', '/')}\"];"); mathematicaLink.WaitAndDiscardAnswer(); }
private static object ReadSingleItemAsType(string type, IKernelLink link) { object res = null; switch (type) { case "Text": { res = link.GetString(); break; } case "Integer": { res = link.GetInteger(); break; } case "Number": { res = link.GetDouble(); break; } case "Boolean": { res = link.GetBoolean(); break; } case "Any": { res = ReadAsAny(link); break; } case "Expr": { res = new ExprType(link.GetExpr()); break; } } return(res); }
public static int GetSamplingRateFromWav(IKernelLink ml, string path) { object obj = null; var wavCommandFormat = string.Format(@"Import[""{0}"" , ""SampleRate"" ]", path.Replace("\\", "\\\\")); ml.Evaluate(wavCommandFormat); ml.WaitForAnswer(); try { obj = ml.GetObject(); } catch (Exception e) { Console.WriteLine(e); return(-1); } return((int)obj); }
internal static void discardNext(IKernelLink ml) { switch (ml.GetNextExpressionType()) { case ExpressionType.Integer: ml.GetInteger(); break; case ExpressionType.Real: ml.GetDouble(); break; case ExpressionType.Boolean: case ExpressionType.Symbol: ml.GetSymbol(); break; case ExpressionType.String: ml.GetString(); break; case ExpressionType.Object: ml.GetObject(); break; // We would get an exception if we called GetComplex() and no complex class was set. case ExpressionType.Complex: case ExpressionType.Function: { IMathLink loop = MathLinkFactory.CreateLoopbackLink(); try { loop.TransferExpression(ml); } finally { loop.Close(); } break; } default: System.Diagnostics.Debug.Fail("Unhandled ExpressionType enum value in Utils.discardNext()."); break; } }
public static IUnityContainer CreateContainer() { IKernelLink mathEngine = null; try { MathLinkFactory.CreateKernelLink(); } catch (Exception e) { throw new Exception("WolframMathematica wasn't found on machine.", e); } IUnityContainer container = new UnityContainer() .RegisterInstance(mathEngine) .RegisterType <IMinimizationStrategy, X2MinimizationStrategy>("X2") .RegisterType <IMinimizationStrategy, LeastSquaresMinimizationStrategy>("LeastSquares"); return(container); }
public static IKernelLink GetKernel() { if (kernelLink == null) { String args = "-linkmode launch -linkname \"" + Environs.FileSystem.Paths["mathPath"] + "\""; if ((String)Environs.Info["mlArgs"] != null) args = (String)Environs.Info["mlArgs"]; try { kernelLink = MathLinkFactory.CreateKernelLink(args); kernelLink.WaitAndDiscardAnswer(); } catch(MathLinkException) { Console.WriteLine("Failed to open the link to Mathematica"); } } return kernelLink; }
// Special method for reading results typed as "Any". We want native objects for simple types like int, double, // arbitrary object refs as objects (let Grasshopper internals worry about wrapping in IGH_Goo), and Expr for anything else. // Note that we don't have to worry here about list/tree access type, because this is only called either for // leaf elements, or to get whole nested lists as a single item for DataAccess.item slots. private static object ReadAsAny(IKernelLink link) { ILinkMark mark = link.CreateMark(); try { ExpressionType leafExprType = link.GetNextExpressionType(); link.SeekMark(mark); switch (leafExprType) { case ExpressionType.Integer: return(link.GetInteger()); case ExpressionType.Real: return(link.GetDouble()); case ExpressionType.String: case ExpressionType.Symbol: return(link.GetString()); case ExpressionType.Object: return(link.GetObject()); case ExpressionType.Boolean: return(link.GetBoolean()); case ExpressionType.Complex: // TODO: Don't have any idea how this is handled elsewhere return(link.GetComplex()); case ExpressionType.Function: return(new ExprType(link.GetExpr())); default: // Just to satisfy the compiler. return(null); } } finally { link.DestroyMark(mark); } }
public static IKernelLink GetKernel() { if (kernelLink == null) { String args = "-linkmode launch -linkname \"" + Environs.FileSystem.Paths["mathPath"] + "\""; if ((String)Environs.Info["mlArgs"] != null) { args = (String)Environs.Info["mlArgs"]; } try { kernelLink = MathLinkFactory.CreateKernelLink(args); kernelLink.WaitAndDiscardAnswer(); } catch (MathLinkException) { Console.WriteLine("Failed to open the link to Mathematica"); } } return(kernelLink); }
/// <summary> /// Creates and connects the link, if it has not already been connected. /// </summary> /// <remarks> /// This will launch the kernel unless you have set the <see cref="Link"/> or <see cref="LinkArguments"/> /// properties. /// <para> /// This method is called automatically by <see cref="Compute"/>, but you can call it yourself if you want to /// force the kernel to launch before any computations are actually triggered. /// </para> /// </remarks> /// public void Connect() { if (!isConnected) { if (ml == null) { ml = linkArgs == null?MathLinkFactory.CreateKernelLink() : MathLinkFactory.CreateKernelLink(linkArgs); } ml.Yield += new YieldFunction(yielder); ml.Connect(); ml.Evaluate("Needs[\"NETLink`\"]"); // If we launched the kernel, we will get the first In[1] prompt. Either way, we get a // ReturnPacket from the Needs call. PacketType pkt = ml.WaitForAnswer(); ml.NewPacket(); if (pkt == PacketType.InputName) { ml.WaitAndDiscardAnswer(); } ml.PacketArrived += new PacketHandler(MathKernelPacketHandler); isConnected = true; } }
public List <Vector> MathDraw(string kappa, string range) { IKernelLink ml = null; List <Vector> outputCurve = new List <Vector>(); try { ml = MathLinkFactory.CreateKernelLink(mlArgs); ml.WaitAndDiscardAnswer(); ml.Evaluate("k[t_]=" + kappa); ml.WaitAndDiscardAnswer(); ml.Evaluate("range = " + range); ml.WaitAndDiscardAnswer(); ml.Evaluate("Needs[\"DrawCurve`\"]"); ml.WaitAndDiscardAnswer(); ml.Evaluate("DrawCurve[k,range]"); ml.WaitForAnswer(); double[,] CurveArray = (double[, ])ml.GetArray(typeof(double), 2); int rows = CurveArray.GetLength(0); int cols = CurveArray.GetLength(1); for (int i = 0; i < rows; i++) { outputCurve.Add(new Vector(CurveArray[i, 0], CurveArray[i, 1], 0)); } } catch (Exception ee) { MessageBox.Show("Error: " + ee.Message); } finally { //tidy everything up ml.Close(); } return(outputCurve); }
public static T Evaluate <T>(string evaluate, Func <IKernelLink, T> GetT) { IKernelLink ml = HMathLinkFactory.CreateKernelLink(); ml.WaitAndDiscardAnswer(); ml.Evaluate(evaluate); ml.WaitForAnswer(); T result; try { result = GetT(ml); //result = ml.GetDoubleArray(); //result = ml.GetObject(); } catch { result = default(T); //result = null; } ml.Close(); return(result); }
// Sepcial exceptions are sent as specialException[tag_String, typeName_String, memberName_String]. Generic exceptions are sent as // strings. internal void writeToLink(IKernelLink ml) { if (InnerException == null) { // A special exception that Mathematica code should know about (such as NET::methodnotfound). ml.PutFunction(Install.MMA_SPECIALEXCEPTION, 3); ml.Put(tag); ml.Put(memberName); ml.Put(typeName); } else { // Some exception not specific to the workings of ObjectHandler (such as InvocationTargetExceptions // thrown by the Invoke() call). These go as NET::excptn messages with their text just coming from // the exception itself. Exception exceptionToReport = InnerException; if (exceptionToReport is System.Reflection.TargetInvocationException) { exceptionToReport = exceptionToReport.InnerException; } // CR-LFs produce two newlines in the front end, so drop them. ml.Put(exceptionToReport.ToString().Replace("\r\n", "\n")); } }
/// <summary> /// Constructs a new MathKernel object that uses the specified link. /// </summary> /// <remarks> /// Use this constructor to "attach" this MathKernel to an existing link. /// </remarks> /// public MathKernel(IKernelLink ml) { this.ml = ml; }
private void startToolStripMenuItem_Click(object sender, EventArgs e) { if (count != 0 || firstIndicator == true) t.Start(); else { frmWorking fw2 = new frmWorking(); fw2.Show(); fw2.Refresh(); ml = MathLinkFactory.CreateKernelLink(); ml.WaitAndDiscardAnswer(); //load the prepared package ml.Evaluate(@"<<C:\ChaosWheel\ChaosWheel2.m"); //ml.Evaluate(path); ml.WaitAndDiscardAnswer(); string input = string.Format("ChaosWheel2[{0},{1},{2},{3},{4},{5},{6},{7},{8}]", paras.R, paras.Sigma, paras.Rho, paras.K, paras.QInflow, paras.Qc, paras.Numb, paras.Tlength, paras.Omega); ml.Evaluate(input); // went for 45 seconds on time interval of 10 ml.WaitForAnswer(); datalist = (double[,])ml.GetArray(typeof(double), 2); numrows = datalist.GetLength(0); numcolumns = datalist.GetLength(1); fw2.Close(); t.Start(); } }
public X2MinimizationStrategy(IKernelLink kernel) { _kernel = kernel; }
// M code must ensure that the only types that can arrive in this function are ones that are currently handled here. public static bool ReadAndStoreResult(string type, int index, IKernelLink link, IGH_DataAccess DA, GH_ParamAccess accessType, GH_Component component) { try { switch (accessType) { case GH_ParamAccess.item: { object res = ReadSingleItemAsType(type, link); DA.SetData(index, res); break; } case GH_ParamAccess.list: { ILinkMark mark = link.CreateMark(); int length = 1; bool isList = false; try { length = link.CheckFunction("List"); isList = true; } catch (MathLinkException) { link.ClearError(); } finally { link.SeekMark(mark); link.DestroyMark(mark); } if (isList) { IList list = ReadListOfItemsAsType(type, link); DA.SetDataList(index, list); } else { object item = ReadSingleItemAsType(type, link); DA.SetData(index, item); } break; } case GH_ParamAccess.tree: { // Quick and dirty method. Only support numbers. Read as Expr, then use Dimensions, etc. // TODO: Handle objects. See how it is done in ReadSingleItemAsType(). // This read-as-expr method shows problems for tree type. It would be better, for tree, to not use // the expr, but rather re-read the data from the link (as is done for item, list). In the curremt // method, I don't see any good way to handle "Any". // WAIT, IT'S WORSE. Expr.AsArray() only does Integer, Real, and only up to depth 2. ILinkMark mark = link.CreateMark(); try { Expr e = link.GetExpr(); int[] dims = e.Dimensions; if (dims.Length == 0) { link.SeekMark(mark); object res = ReadSingleItemAsType(type, link); DA.SetData(index, res); } else if (dims.Length == 1) { link.SeekMark(mark); IList list = ReadListOfItemsAsType(type, link); DA.SetDataList(index, list); } else if (dims.Length == 2) { // This code could be cleaner with GH_Structure, but I dont quite understand that class... switch (type) { case "Number": { DataTree <double> tree = new DataTree <double>(); Array dataArray = e.AsArray(ExpressionType.Real, 2); for (int i = 0; i < dims[0]; i++) { GH_Path pth = new GH_Path(i); for (int j = 0; j < dims[1]; j++) { tree.Add((double)dataArray.GetValue(i, j), pth); } } DA.SetDataTree(index, tree); break; } case "Integer": { DataTree <int> tree = new DataTree <int>(); Array dataArray = e.AsArray(ExpressionType.Integer, 2); for (int i = 0; i < dims[0]; i++) { GH_Path pth = new GH_Path(i); for (int j = 0; j < dims[1]; j++) { tree.Add((int)dataArray.GetValue(i, j), pth); } } DA.SetDataTree(index, tree); break; } default: // Can't handle this. return(false); } } else { // TODO. At least set a RuntimeMessage before returning false. return(false); } } finally { link.DestroyMark(mark); } break; // Problem with the read-and-fill-element-by-element approach is that this is a GH_Structure<IGH_Goo>, // so I need to create an IGH_Goo pbjectout of every piece of data. But there are zillions of IGH_Goo // objects out there. I don't want to map every object to its IGH_Goo type (e.g., Circle --> GH_Circle). // For lists, I could simply create a List<anything> and apparently it gets converted to the appopriate // IGH_Goo object later on. But with trees, I don't see the corresponding technique. Compare the signature // of DA.SetDataList() and DA.SetDataTree(). /* * ILinkMark mark3 = link.CreateMark(); * int length = 1; * try { * length = link.CheckFunction("List"); * // Don't catch; allow to fail. Must be a list arriving for tree results. * } finally { * link.DestroyMark(mark3); * } * GH_Structure<IGH_Goo> structure = new GH_Structure<IGH_Goo>(); * GH_Path path = new GH_Path(0); * int pathLen = 1; * int pathIndex = 0; * for (int i = 0; i < length; i++) { * if (isListWaitingOnLink(link)) { * path. * } else { * structure.Append( * } * } */ } } } catch (Exception) { component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Unexpected type of result from Wolfram Engine"); link.ClearError(); link.NewPacket(); return(false); } return(true); }
/// <summary> /// This is the root method where the .NET runtime launched by InstallNET[] spends its life. It just sits here /// waiting for input to arrive from <i>Mathematica</i>. /// </summary> /// public static void Run() { Application.ThreadException += new ThreadExceptionEventHandler(onThreadException); ml.Yield += yieldFunctionWithEvents; try { while (true) { if (isModal || isSharing) { // Polling is much less efficient than blocking. It is used only in special circumstances (such as while the kernel is // executing DoModal[], or after the kernel has called nAllowUIComputations[True]). // If we are blocking in NextPacket(), the yield function is dispatching messages. But when we are // polling Ready(), the yielder is not called, so we need to arrange for messages to be processed. Application.DoEvents(); if (!ml.Ready) { Thread.Sleep(sleepInterval); } lock (ml) { try { if (ml.Error != 0) { throw new MathLinkException(ml.Error, ml.ErrorMessage); } if (ml.Ready) { PacketType pkt = ml.NextPacket(); ml.HandlePacket(pkt); ml.NewPacket(); } } catch (MathLinkException e) { // 11 is "other side closed link"; not sure why this succeeds clearError, but it does. if (e.ErrCode == 11 || !ml.ClearError()) { return; } ml.NewPacket(); } } } else { // Use blocking style (dive right into MLNextPacket and block there). Much more efficient. lock (ml) { try { PacketType pkt = ml.NextPacket(); ml.HandlePacket(pkt); ml.NewPacket(); } catch (MathLinkException e) { // 11 is "other side closed link"; not sure why this succeeds clearError, but it does. if (e.ErrCode == 11 || !ml.ClearError()) { return; } ml.NewPacket(); } } // end synchronized } } } finally { // Get here on unrecoverable MathLinkException, ThreadDeath exception caused by "hard" aborts // from Mathematica (see KernelLinkImpl.msgHandler()), or other Error exceptions (except during invoke()). if (quitWhenLinkEnds) { ml.Close(); ml = null; //System.Diagnostics.Trace.Flush(); Application.Exit(); } } }
public LeastSquaresMinimizationStrategy(IKernelLink kernel) { _kernel = kernel; }
private void FrmMain_Load(object sender, EventArgs e) { SetupTransform(); //receive user input // some initial values paras.R = 7; paras.QInflow = 10; paras.Qc = 10; paras.Sigma = 10; paras.Rho = 28; paras.Numb = 8; paras.Tlength = 5; paras.K = 1; paras.Omega = 0.1f; frmParameterDialog pd = new frmParameterDialog(); pd.Text = "Enter the parameter values for the system"; // just some default values pd.Data.R_ = paras.R; pd.Data.QInflow_ = paras.QInflow; pd.Data.Qc_ = paras.Qc; pd.Data.K_ = paras.K; pd.Data.Sigma_ = paras.Sigma; pd.Data.Rho_ = paras.Rho; pd.Data.Numb_ = paras.Numb; pd.Data.Tlength_ = paras.Tlength; pd.Data.Omega_ = paras.Omega; DialogResult d = pd.ShowDialog(); if (d == DialogResult.OK) { paras.R = pd.Data.R_; paras.QInflow = pd.Data.QInflow_; paras.Qc = pd.Data.Qc_; paras.K = pd.Data.K_; paras.Sigma = pd.Data.Sigma_; paras.Rho = pd.Data.Rho_; paras.Numb = pd.Data.Numb_; paras.Tlength = pd.Data.Tlength_; paras.Omega = pd.Data.Omega_; } // set the initial positions of the buckets for (i = 0; i < paras.Numb; i++) { bucketlist.Add(new Bucket()); } for (j = 0; j < bucketlist.Count; j++) { bucketlist[j].Width = 3.5f * (float)Math.Pow(0.9, paras.Numb - 8); // when there are 8 buckets, looks best if bucket width and height is 3.5 bucketlist[j].Height = 3.5f * (float)Math.Pow(0.9, paras.Numb - 8); // adjust depending on number of buckets according to this formula: width = 3.5*(0.9)^(n-8) bucketlist[j].X = (float)(paras.R * Math.Sin(-theta - j * 2 * Math.PI / bucketlist.Count)); bucketlist[j].Y = (float)(-paras.R * Math.Cos(-theta - j * 2 * Math.PI / bucketlist.Count)); } frmWorking fw1 = new frmWorking(); fw1.Show(); fw1.Refresh(); //System.Threading.Thread.Sleep(100); ml = MathLinkFactory.CreateKernelLink(); ml.WaitAndDiscardAnswer(); //load the prepared package ml.Evaluate(@"<<C:\ChaosWheel\ChaosWheel2.m"); //dont need the result ml.WaitAndDiscardAnswer(); //call method for new theta string input = string.Format("ChaosWheel2[{0},{1},{2},{3},{4},{5},{6},{7},{8}]", paras.R, paras.Sigma, paras.Rho, paras.K, paras.QInflow, paras.Qc, paras.Numb, paras.Tlength, paras.Omega); ml.Evaluate(input); // went for 45 seconds on time interval of 10 ml.WaitForAnswer(); //move the system according to theta //thetalist = (double[])ml.GetArray(typeof(double),1); datalist = (double[, ])ml.GetArray(typeof(double), 2); numrows = datalist.GetLength(0); numcolumns = datalist.GetLength(1); firstIndicator = true; fw1.Close(); }
public static Complex[] GetFourierTransform(IKernelLink ml, double[] data) { object o = null; Expr template = new Expr(ExpressionType.Symbol,"Fourier"); Expr arg = new Expr(data); Expr quer = new Expr(template, new object[] { arg }); ml.Evaluate(quer); ml.WaitForAnswer(); try { o = ml.GetObject(); } catch (Exception e) { Console.WriteLine(e); try { var problem = ml.GetSymbol(); Console.WriteLine(problem); } catch (Exception e2) { Console.WriteLine(e2); } return null; } var cast = (Complex [])o; return cast; }
public static int GetSamplingRateFromWav(IKernelLink ml, string path) { object obj = null; var wavCommandFormat = string.Format(@"Import[""{0}"" , ""SampleRate"" ]", path.Replace("\\","\\\\") ); ml.Evaluate(wavCommandFormat); ml.WaitForAnswer(); try { obj = ml.GetObject(); } catch (Exception e) { Console.WriteLine(e); return -1; } return (int)obj; }
public static double[] GetDataFromWav(IKernelLink ml, string path) { object obj = null; var wavCommandFormat = string.Format(@"Data2 = Import[""{0}"" , ""Data""]", path.Replace("\\","\\\\") ); ml.Evaluate(wavCommandFormat); PacketType p = ml.WaitForAnswer(); object tempo = checkPacketType(p); try { obj = ml.GetObject(); } catch (Exception e) { Console.WriteLine(e); return null; } var cast = (double [,] ) obj; var res = new double[cast.GetLength(1)]; for (var ii = 0; ii < cast.GetLength(1); ++ii) //TODO: Kill this for loop! there ought to be a native way { res[ii] = cast[0, ii];//Throw away one channel, we're not stereo anyways } return res; }
/// <summary> /// This method is used for calling members on COM objects via IDispatch. /// </summary> /// <remarks> /// All objects that get here will have type __ComObject. They may have been "typed" as a .NET interface, but if /// the member in question was found in that interface the call would have been handled through normal channels. /// When we get here we have given up hope for any help from the managed side of things. /// Note that in one case we can be calling a true managed method here. This is the case where a method from the Object class /// (e.g., GetHashCode()) is called on a COM object typed as a .NET interface. The method is not part of the interface, so we /// get here, thinking it is a COM method not part of the managed interface. But no matter--the technique used here to call /// methods works for managed methods in the Object class as well as true COM calls via IDispatch (note that it is really the /// MarshalByRefObject class that the methods might belong to, as that is the parent class of __ComObject). /// </remarks> /// <param name="ml"></param> /// <param name="obj"></param> /// <param name="memberName"></param> /// <param name="callType"></param> /// <param name="argTypes"></param> /// <param name="outParams"></param> /// <returns>the result of the call</returns> internal object callDispatch(IKernelLink ml, object obj, string memberName, int callType, int[] argTypes, out OutParamRecord[] outParams) { System.Diagnostics.Debug.Assert(obj != null && obj.GetType().Name == "__ComObject"); outParams = null; Type[] paramTypes; PARAMFLAG[] paramFlags; bool isBeingCalledWithZeroArgs = argTypes.Length == 0; // 'endsWithParamArray' tells us if the function ends in a VB-style ParamArray arg. Args for a ParamArray must be // supplied as a sequence, not packed into a list. If there is a ParamArray, COMUtilities.getMemberInfo() won't // return a paramTypes or paramFlags entry for it (it always shows up as a ByRef array of Variant, but since the args // must be sent as a sequence it is easiest to treat it specially). bool endsWithParamArray; // We cannot just call InvokeMember even if we know the args can be converted, because we don't know if the member // name needs U -> _ conversion, or if any parameters are out params. // Note that isValidMember does not guarantee it's valid, only that it is not _known_ to be invalid. If there is no // type info available, isValidMember will be true. MemberName is byref since it may need to be massaged (U -> _) by // GetMemberInfo(). ParamTypes amd paramFlags values only relevant if function return value is true, in which case // they are set to null if no type info is available or if there are no args being passed to this method (in which // case type info is irrelevant). bool isValidMember = COMUtilities.GetMemberInfo(obj, ref memberName, callType, isBeingCalledWithZeroArgs, out paramTypes, out paramFlags, out endsWithParamArray); if (!isValidMember) { string err; if (callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_GET || callType == Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_SET) { err = Install.COM_PROP_NOT_FOUND; } else { err = Install.COM_METHOD_NOT_FOUND; } throw new CallNETException(err, "System.__ComObject", memberName); } // Note this will also get the value false if isBeingCalledWithZeroArgs==true. bool typeInfoIsAvailable = paramTypes != null; // If the method ends with a VB-style ParamArray arg, all these params are out params, but they don't show up at all // in paramFlags, so we use this information to juice the initial value of hasOutParams. bool hasOutParams = endsWithParamArray; // If type info is available, we can extract some information from it. We check the arg count for too few and too many. // We also decide whether the args can be converted automatically by the innards of the IDispatch mechanism. // This means checking whether any of the args are out params (ByRef), because COM will automatically convert // args to the appropriate type of Variant unless it is ByRef (this conversion includes narrowing or widening primitive // types like ints and reals). This means that we don't need to care that we will read an integer as type int, but // the arg slot is a short. Arrays are always ByRef so they cannot be converted automatically. If the args can be // converted automatically, we can read them as their most natural type; otherwise we have to read them as the proper // type for that arg slot or COM will give a "Type mismatch" error. // Note that we will not enter this block if 0 args are being passed. This means that for 0-arg // calls, we will not detect it here if more than 0 args are required. Instead, an error will occur during InvokeMember(). // That's not a big problem, since the error will say something about the number of args. We prefer the optimization of // not taking the time to look up argument type info (in COMUtilities.GetMemberInfo() above) to the goal of getting // the cleanest possible error messages. if (typeInfoIsAvailable) { // Get this check out of the way first. Note that it is OK to pass more args than there are entries in // paramFlags if the function ends with a ParamArray. if (argTypes.Length > paramFlags.Length && !endsWithParamArray) { // Too many args were passed. throw new CallNETException(Install.METHOD_ARG_COUNT, "System.__ComObject", memberName); } // At this point, argTypes.Length could be greater or less than paramFlags.Length. Less if we are leaving out optional // params, more if we are passing args to a ParamArray at the end. int minimumAllowableArgCount = 0; for (int i = 0; i < Math.Max(paramFlags.Length, argTypes.Length); i++) { // If not an optional param, increment minimumAllowableArgCount. if (i < paramFlags.Length && (paramFlags[i] & PARAMFLAG.PARAMFLAG_FOPT) == 0) { minimumAllowableArgCount++; } // Decide if this arg can be converted to the correct type automatically by the innards of the IDispatch mechanism. if (i < argTypes.Length) { int argType = argTypes[i]; if (argType == Install.ARGTYPE_OTHER) { throw new CallNETException(Install.METHOD_BAD_ARGS, "System.__ComObject", memberName); } else if (i < paramFlags.Length && (paramFlags[i] & PARAMFLAG.PARAMFLAG_FOUT) != 0) { // Out params (ByRef) cannot be converted. hasOutParams = true; } } } if (argTypes.Length < minimumAllowableArgCount) { // Too few args were passed. throw new CallNETException(Install.METHOD_ARG_COUNT, "System.__ComObject", memberName); } } object[] args = new object[argTypes.Length]; try { for (int i = 0; i < argTypes.Length; i++) { // Get this one out of the way first. if (argTypes[i] == Install.ARGTYPE_MISSING) { args[i] = System.Reflection.Missing.Value; ml.GetSymbol(); } else if (!typeInfoIsAvailable || i >= paramFlags.Length /*|| argCanBeConvertedAutomatically[i]*/) { args[i] = ml.GetObject(); } else if ((paramFlags[i] & PARAMFLAG.PARAMFLAG_FOUT) != 0 && (paramFlags[i] & PARAMFLAG.PARAMFLAG_FIN) == 0) { // Out-only params can be discarded from the link. Utils.discardNext(ml); args[i] = null; } else { args[i] = Utils.readArgAs(ml, argTypes[i], paramTypes[i]); } } } catch (Exception) { // Typically ArgumentException from Utils.readArgAs(). Don't need a special COM_ version of this error message. throw new CallNETException(Install.METHOD_BAD_ARGS, "System.__ComObject", memberName); } // The type will be __ComObject, but we must get it from the object itself (cannot use typeof()). Type t = obj.GetType(); object result = null; switch (callType) { case Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_GET: result = t.InvokeMember(memberName, BindingFlags.GetProperty, null, obj, args); break; case Install.CALLTYPE_FIELD_OR_SIMPLE_PROP_SET: result = t.InvokeMember(memberName, BindingFlags.SetProperty, null, obj, args); break; case Install.CALLTYPE_METHOD: // Recall that non-static parameterized prop gets masquerade as CALLTYPE_METHOD, hence the added BindingFlag.GetProperty // in the InvokeMember() call. Example is worksheet@Range["A1"]. if (hasOutParams && args.Length > 0) { // paramModifiers allows us to have out params returned with new values. ParameterModifier pm = new ParameterModifier(args.Length); // Note that if i >= paramFlags.Length we are daling with the trailing sequence of args to a ParamArray. // Such args are always out params so they need a ParameterModifier (and they don't show up in paramFlags). for (int i = 0; i < args.Length; i++) { pm[i] = i >= paramFlags.Length || (paramFlags[i] & PARAMFLAG.PARAMFLAG_FOUT) != 0; } ParameterModifier[] paramModifiers = new ParameterModifier[] { pm }; result = t.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, null, obj, args, paramModifiers, null, null); } else { result = t.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, null, obj, args); } break; case Install.CALLTYPE_PARAM_PROP_GET: // Don't think we can ever get here, as only static param prop gets come in as CALLTYPE_PARAM_PROP_GET. // Still I will leave this code in, in case instance param prop gets ever get properly distinguished on the M side. result = t.InvokeMember(memberName, BindingFlags.GetProperty, null, obj, args); break; case Install.CALLTYPE_PARAM_PROP_SET: result = t.InvokeMember(memberName, BindingFlags.SetProperty, null, obj, args); break; } // Now do out params. if (hasOutParams) { for (int i = 0; i < args.Length; i++) { if (i >= paramFlags.Length || (paramFlags[i] & PARAMFLAG.PARAMFLAG_FOUT) != 0) { if (outParams == null) { outParams = new OutParamRecord[args.Length]; } outParams[i] = new OutParamRecord(i, args[i]); } } } return(result); }
// probably create a LinkUtils class for this and other link-related funcs.... // OK to throw various exceptions trying to read data as the wrong type. internal static object readArgAs(IKernelLink ml, int argType, Type t) { // For our purposes here, type& is the same as type. Thus we drop the &, which will otherwise // confound our type testing below. if (t.IsByRef) { t = t.GetElementType(); } if (t == typeof(Expr)) { return(ml.GetExpr()); } if (argType == Install.ARGTYPE_OBJECTREF || argType == Install.ARGTYPE_NULL) { object obj = ml.GetObject(); if (Object.ReferenceEquals(obj, System.Reflection.Missing.Value)) { // Don't try to convert Missing. Just pass it on. return(obj); } else if ((Utils.IsTrulyPrimitive(t) || t == typeof(decimal)) && obj.GetType() != t) { // If the type to read as is primitive/numeric but the arriving arg is an object ref, convert the object // to the correct type. We are just casting to the correct type here in the case where the arg arrives as an // object ref instead of a raw value. return(Convert.ChangeType(obj, t)); } else { return(obj); } } if (argType == Install.ARGTYPE_MISSING) { // Throw away the "Default" symbol. ml.GetSymbol(); return(System.Reflection.Missing.Value); } // Allow enums to be sent as ints from Mathematica. if (argType == Install.ARGTYPE_INTEGER && t.IsEnum) { Type enumBaseType = Enum.GetUnderlyingType(t); object val = readArgAs(ml, argType, enumBaseType); // Enum.IsDefined(t, val) is not suitable for testing the validity of the value unless the enum is _not_ a bitflag, // because a bitor of values will not pass that test. We just forego range checking for bitflags enums. if (!Enum.IsDefined(t, val) && t.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0) { throw new MathLinkException(MathLinkException.MLE_BAD_ENUM, "Enum value " + val + " out of range for type " + t.FullName + "."); } return(Enum.ToObject(t, val)); } if ((argType == Install.ARGTYPE_INTEGER || argType == Install.ARGTYPE_REAL || argType == Install.ARGTYPE_COMPLEX) && t == ml.ComplexType) { return(ml.GetComplex()); } // We have already handled the cases where the arg on the link is an object ref and where it is // an int but the type to read as is an enum. Also if t is the complex type and args match that. switch (Type.GetTypeCode(t)) { case TypeCode.Object: { // Note that we allow "weak" boxing here in that you can pass a primitive or array from M for an // object argument. But you don't get control of the type that it is read as (e.g., M Integer // goes to .NET int, not byte). if (argType == Install.ARGTYPE_INTEGER) { return(ml.GetInteger()); } else if (argType == Install.ARGTYPE_REAL) { return(ml.GetDouble()); } else if (argType == Install.ARGTYPE_STRING) { return(ml.GetString()); } else if (argType == Install.ARGTYPE_NULL) { ml.GetSymbol(); return(null); } else if (argType == Install.ARGTYPE_BOOLEAN) { return(ml.GetBoolean()); } else if (argType == Install.ARGTYPE_COMPLEX) { return(ml.GetComplex()); } else if (argType == Install.ARGTYPE_OTHER) { throw new ArgumentException(); } else { // VECTOR, MATRIX, TENSOR3, LIST if (t == typeof(Array) || t == typeof(object)) { return(readArbitraryArray(ml, typeof(Array))); } else if (t.IsArray) { Type elementType = t.GetElementType(); // All arrays-of-arrays are read the slow way. if (elementType.IsArray) { return(readArbitraryArray(ml, t)); } else { // Must be an array like [,...], not [,...][,...]. return(ml.GetArray(elementType, t.GetArrayRank())); } } else if (t.IsPointer && argType == Install.ARGTYPE_VECTOR) { // Allow flat M lists to be passed for pointer args. Type elementType = t.GetElementType(); return(readArgAs(ml, Install.ARGTYPE_VECTOR, TypeLoader.GetType(elementType.FullName + "[]", true))); } else { throw new ArgumentException(); } } } case TypeCode.Byte: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((byte)ml.GetInteger()); case TypeCode.SByte: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((sbyte)ml.GetInteger()); case TypeCode.Char: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((char)ml.GetInteger()); case TypeCode.Int16: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((short)ml.GetInteger()); case TypeCode.UInt16: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((ushort)ml.GetInteger()); case TypeCode.Int32: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return(ml.GetInteger()); case TypeCode.UInt32: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((uint)ml.GetDecimal()); case TypeCode.Int64: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((long)ml.GetDecimal()); case TypeCode.UInt64: if (argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((ulong)ml.GetDecimal()); case TypeCode.Single: if (argType != Install.ARGTYPE_REAL && argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return((float)ml.GetDouble()); case TypeCode.Double: if (argType != Install.ARGTYPE_REAL && argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return(ml.GetDouble()); case TypeCode.Decimal: if (argType != Install.ARGTYPE_REAL && argType != Install.ARGTYPE_INTEGER) { throw new ArgumentException(); } return(ml.GetDecimal()); case TypeCode.Boolean: if (argType != Install.ARGTYPE_BOOLEAN) { throw new ArgumentException(); } return(ml.GetBoolean()); case TypeCode.String: if (argType != Install.ARGTYPE_STRING) { throw new ArgumentException(); } return(ml.GetString()); case TypeCode.DateTime: return((DateTime)ml.GetObject()); case TypeCode.DBNull: // ??? ml.GetSymbol(); return(DBNull.Value); default: // No cases unhandled. throw new ArgumentException(); } }
private void FrmMain_Load(object sender, EventArgs e) { SetupTransform(); //receive user input // some initial values paras.R = 7; paras.QInflow = 10; paras.Qc = 10; paras.Sigma = 10; paras.Rho = 28; paras.Numb = 8; paras.Tlength = 5; paras.K = 1; paras.Omega = 0.1f; frmParameterDialog pd = new frmParameterDialog(); pd.Text = "Enter the parameter values for the system"; // just some default values pd.Data.R_ = paras.R; pd.Data.QInflow_ = paras.QInflow; pd.Data.Qc_ = paras.Qc; pd.Data.K_ = paras.K; pd.Data.Sigma_ = paras.Sigma; pd.Data.Rho_ = paras.Rho; pd.Data.Numb_ = paras.Numb; pd.Data.Tlength_ = paras.Tlength; pd.Data.Omega_ = paras.Omega; DialogResult d = pd.ShowDialog(); if (d == DialogResult.OK) { paras.R = pd.Data.R_; paras.QInflow = pd.Data.QInflow_; paras.Qc = pd.Data.Qc_; paras.K = pd.Data.K_; paras.Sigma = pd.Data.Sigma_; paras.Rho = pd.Data.Rho_; paras.Numb = pd.Data.Numb_; paras.Tlength = pd.Data.Tlength_; paras.Omega = pd.Data.Omega_; } // set the initial positions of the buckets for (i = 0; i < paras.Numb; i++) { bucketlist.Add(new Bucket()); } for (j = 0; j < bucketlist.Count; j++) { bucketlist[j].Width = 3.5f * (float)Math.Pow(0.9, paras.Numb - 8); // when there are 8 buckets, looks best if bucket width and height is 3.5 bucketlist[j].Height = 3.5f * (float)Math.Pow(0.9, paras.Numb - 8); // adjust depending on number of buckets according to this formula: width = 3.5*(0.9)^(n-8) bucketlist[j].X = (float)(paras.R * Math.Sin(-theta - j * 2 * Math.PI / bucketlist.Count)); bucketlist[j].Y = (float)(-paras.R * Math.Cos(-theta - j * 2 * Math.PI / bucketlist.Count)); } frmWorking fw1 = new frmWorking(); fw1.Show(); fw1.Refresh(); //System.Threading.Thread.Sleep(100); ml = MathLinkFactory.CreateKernelLink(); ml.WaitAndDiscardAnswer(); //load the prepared package ml.Evaluate(@"<<C:\ChaosWheel\ChaosWheel2.m"); //dont need the result ml.WaitAndDiscardAnswer(); //call method for new theta string input = string.Format("ChaosWheel2[{0},{1},{2},{3},{4},{5},{6},{7},{8}]", paras.R, paras.Sigma, paras.Rho, paras.K, paras.QInflow, paras.Qc, paras.Numb, paras.Tlength, paras.Omega); ml.Evaluate(input); // went for 45 seconds on time interval of 10 ml.WaitForAnswer(); //move the system according to theta //thetalist = (double[])ml.GetArray(typeof(double),1); datalist = (double[,])ml.GetArray(typeof(double), 2); numrows = datalist.GetLength(0); numcolumns = datalist.GetLength(1); firstIndicator = true; fw1.Close(); }
protected override void SolveInstance(IGH_DataAccess DA) { ` GetData ` // Final, optional link input param is always present. LinkType linkType = null; DA.GetData(` InputArgCount `, ref linkType); IKernelLink link = linkType != null ? linkType.Value : Utils.GetLink(); // Send initialization code and saved defs. try { if (` UseInit `) { link.Evaluate("ReleaseHold[\"" + ` Initialization ` + "\"]"); link.WaitAndDiscardAnswer(); } if (` UseDefs `) { link.Evaluate(` Definitions `); link.WaitAndDiscardAnswer(); } } catch (MathLinkException exc) { link.ClearError(); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "WSTPException communicating with Wolfram Engine: " + exc); return; } // Now begin sending the actual computation. try { link.PutFunction("EvaluatePacket", 1); link.PutNext(ExpressionType.Function); link.PutArgCount(` InputArgCount `); if (` HeadIsSymbol `) { link.PutSymbol("`Func`"); } else { // pure function link.PutFunction("ToExpression", 1); link.Put("`Func`"); } ` SendInputParams ` link.EndPacket(); link.WaitForAnswer(); } catch (MathLinkException exc) { link.ClearError(); link.NewPacket(); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "WSTPException communicating with Wolfram Engine: " + exc); return; } // This is one part of a (likely) temporary feature that puts the Expr result on the second output. Expr debuggingExpr = link.PeekExpr(); // Read the result(s) and store them in the DA object. ILinkMark mark = link.CreateMark(); // TODO: ghResultCount is not used, but if we are going to allow multiple outputs, then we have to protect against // users specifying more than one, but only one arrives. This will hang reading the second one. int ghResultCount = 0; bool isGHResult = false; try { ghResultCount = link.CheckFunction("GHResult") - 1; isGHResult = true; } catch (MathLinkException) { link.SeekMark(mark); } finally { link.DestroyMark(mark); } try { if (isGHResult) { ` ReadAndStoreResults ` } else { ` ReadAndStoreResults ` } // This is the second part of the temporary feature that puts the entire result as an Expr on a second output port. DA.SetData(++ghResultCount, new ExprType(debuggingExpr)); // Last output item is always the link. DA.SetData(ghResultCount + 1, new LinkType(link)); } catch (MathLinkException exc) { link.ClearError(); AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "WSTPException communicating with Wolfram Engine while reading results: " + exc); } finally { link.NewPacket(); } }
/// <summary> /// Must always be called before calling into <i>Mathematica</i> from a .NET user-interface action. /// </summary> /// <remarks> /// You should always call RequestTransaction whenever you are preparing to call into <i>Mathematica</i> /// from a .NET user-interface action, like clicking a button. This only applies for code executing in /// a .NET runtime launched from <i>Mathematica</i> by InstallNET[], not if you are launching and controlling /// the kernel from a standalone .NET program. /// <para> /// The only time you do <b>not</b> need to call RequestTransaction before calling into <i>Mathematica</i> /// is when the call is being made during the handling of a call from <i>Mathematica</i> into .NET. In other words, /// when <i>Mathematica</i> is currently in the middle of a call into .NET, it is always safe for calls /// to be made from .NET back into <i>Mathematica</i> (and RequestTransaction does nothing in this circumstance). /// You need RequestTransaction to guard calls that <i>originate</i> in .NET. User interface actions are typical /// examples of such calls, as <i>Mathematica</i> might not currently be ready to accept incoming requests from .NET. /// </para> /// It is safe to call RequestTransaction <i>whenever</i> you call back into <i>Mathematica</i>--if it is not necessary /// then RequestTransaction will simply return immediately. In other words, if you do not understand the exact circumstances /// in which it is necessary, you can err on the side of caution and call it more often than needed. /// <para> /// What RequestTransaction does is check whether it is safe to call into <i>Mathematica</i>. If it is safe, it returns /// immediately. If it is not safe, a <see cref="MathematicaNotReadyException"/> is thrown. You can typically ignore this /// exception and let it propagate up into the .NET event-dispatching mechanism, where it will be caught /// by the internals of .NET/Link and cause a MessageBox to be displayed. /// </para> /// It is safe to call into <i>Mathematica</i> in several circumstances. The first is if the <i>Mathematica</i> functions /// DoNETModal or DoNETModeless are currently running. This is the normal situation when user interface actions that /// call <i>Mathematica</i> are being executed. It is also safe to call into <i>Mathematica</i> when <i>Mathematica</i> /// is in the middle of calling .NET. Finally, it is safe to call into <i>Mathematica</i> if you have launched the /// kernel from your own program instead of running in the .NET runtime launched from <i>Mathematica</i> by InstallNET[]. /// <para> /// Many programmers will never use this method, because they will use the <i>Mathematica</i> function AddEventHandler /// to establish callbacks from .NET into <i>Mathematica</i>. Event handlers created by AddEventHandler handle all details /// of the communication with <i>Mathematica</i> for you (and of course they call RequestTransaction internally). /// </para> /// <example> /// Here is an example of .NET code that is intended to be executed as a result of a user interface action. /// <code> /// IKernelLink ml = StdLink.Link; /// if (ml != null) { /// StdLink.RequestTransaction(); /// // Always lock the link before using it. /// lock (ml) { /// ml.Print("You clicked a button"); /// } /// } /// </code> /// </example> /// <para> /// Note again that this is not the "normal" way you would wire up a Print action to a button click. Instead, /// you would just write something like this in <i>Mathematica</i>: /// <code> /// (* Mathematica code *) /// AddEventHandler[myButton@Click, Print["You clicked a button"]&]; /// </code> /// This discussion about RequestTransaction only applies to programmers who are writing their own custom .NET code. /// </para> /// </remarks> /// <exception cref="MathematicaNotReadyException"> /// If the kernel is not in a state where it is receptive to calls originating in .NET, as described above. /// </exception> /// public static void RequestTransaction() { // requestTransaction must be a no-op under two circumstances. There is no reason // to call requestTransaction in these circumstances, but it must be safe: // - calls being made from a .NET program to a kernel it is $ParentLink'ed to. That is, no Reader thread running. // - calls being made as part of a callback from Mathematica. // This tells us if the Reader thread is not running. if (mainLink == null || !mainLinkHasReader) { return; } // This is the link that the user's subsequent call to StdLink.getLink() will return. Depending on which link // this is, we need to do different things below. IKernelLink linkThatWillBeUsed = Link; // This is an error condition (the user will get an exception later when they call Link and // try to use it), but there is nothing to do here. if (linkThatWillBeUsed == null) { return; } // It's always safe to call on the UI link. if (linkThatWillBeUsed == uiLink) { return; } // We only get here if we are not going to be using the uiLink. This could be because it is a // 5.0 kernel and there is no uiLink, or because we're in the modal state or we're in the // middle of a call from Mathematica. // We cannot use the mainLink if we are already in the middle of NextPacket() on that link. // The only likely scenario for this is that we are in a 5.0 kernel and we are not in the ShareKernel // or modal state. if (Reader.isInsideNextPacket) { //System.Diagnostics.Debug.WriteLine("inside next packet, throwing MathematicaNotReadyException"); throw new MathematicaNotReadyException(MathematicaNotReadyException.KERNEL_NOT_SHARED); } if (Reader.isInModalState) { return; } // If we are in the middle of a callback from Mathematica, handleCallPacket is on the stack, which we can // detect by having the thread represented in stdLinkHash. lock (stdLinkLock) { object key = Thread.CurrentThread; Stack s = (Stack)stdLinkHash[key]; if (s != null && s.Count > 0) { return; } } // We now know that mainLink is the correct link to communicate with. // Kernel is shared, but another link has its attention. if (!Reader.allowUIComputations) { System.Diagnostics.Debug.WriteLine("!allowUIComputations, throwing MathematicaNotReadyException"); throw new MathematicaNotReadyException(MathematicaNotReadyException.FE_HAS_KERNEL_ATTENTION); } }
public Application(IKernelLink kernel) { Kernel = kernel; DoneInitializing = true; }
public WolframMathematicaEvaluationEngine() { _kernel = _container.Resolve <IKernelLink>(); _kernel.WaitAndDiscardAnswer(); }