Brenton Horne Brenton Horne - 16 days ago 5
C++ Question

How to exit GNU Octave, after running an m file, without closing plot windows?

I have been writing a C++ program to solve the problem of the simple pendulum and then plot the result using GNU Octave. It plots the result via this line in my program:

system("./simppenadj.sh");


where
simppenadj.sh
is:

#!/bin/sh
octave --no-gui --persist -q simppenadj.m


and
simppenadj.m
is:

#!/usr/bin/octave
# Plotting simppenadj.txt
A = importdata('simppenadj.txt');
B = importdata('simppenadjdx.txt');
t = A(:,1);
theta = A(:,2);
dtheta = B(:,2);
figure
plot(t,theta)
xlabel('t','FontSize',16,'FontWeight','bold')
ylabel('\theta','FontSize',16,'FontWeight','bold')
title('{d^{2}\theta}/{d{t^{2}}} = -9.8 cos({\theta})','FontSize',18,'FontWeight','bold')
figure
plot(theta,dtheta)
xlabel('\theta','FontSize',16,'FontWeight','bold')
ylabel('d\theta/dt','FontSize',16,'FontWeight','bold')
title('{d^{2}\theta}/{d{t^{2}}} = -9.8 cos({\theta})','FontSize',18,'FontWeight','bold')


Whenever I run my C++ program the CLI of GNU Octave is started (and left opened at the end) and the data is plotted. I do not want the CLI of GNU Octave to be left open, but the only way I know how to get it not to open is to remove the
--persist
option in
simppenadj.sh
which also makes the plots generated by GNU Octave to not be left open. This is a problem, as I want the plots to be left opened after my C++ program has been run. So is there a way to do this?

Answer

You can use the octave API to call the script from within your program. There, create a child process, which calls octave, so the parent process can end. With this, you can keep octave running. With this method, there is no octave CLI, since you do all calls to octave via the API, especially feval.

Unfortunately, the guide on using the API is very bad, but i put something together for you which should work. It basically only reads a script and executes the corresponding function. This is the nice thing about this method: you can write everything using normal octave function/script file methods.

I added the printf statement in the octave file in order to show how you can pass arguments to octave.

main.cpp

#include <iostream>

#include <unistd.h>

#include <octave/oct.h>
#include <octave/octave.h>
#include <octave/parse.h>
#include <octave/toplev.h>

int main()
{
    pid_t pid = fork();

    if(pid != 0) // parent
    {
        std::cout << "parent, exiting\n";
    }
    else
    {
        // arguments for octave
        string_vector argv (2);
        argv(0) = "embedded";
        argv(1) = "-q"; // quiet

        // start octave, run embedded (third parameter == true)
        octave_main (2, argv.c_str_vec (), true);

        // read the script file
        source_file("calc_and_plot.m");

        // call the function with an argument
        octave_value_list in;
        in(0) = "Hello, world.";
        feval("calc_and_plot", in);


        std::cout << "octave (child process) done\n";
        clean_up_and_exit(0); // quit octave. This also quits the program,
                              // so use this together with atexit, if you 
                              // need to do something else after octave exits
    }

    return 0;
}

octave script/function file

function calc_and_plot(str)
    printf('%s\n', str);
    x = linspace(0, 2*pi, 100);
    y = sin(x);
    it = plot(y);
    waitfor(it);
end

Compile the main.cpp with

g++ main.cpp -L/usr/lib/octave-4.0.2 -I/usr/include/octave-4.0.2 -loctave -loctinterp

You have to adjust the paths to your system and octave version. You can also use the mkoctfile command, which basically does the same. You can look at the output of its -p switch, e.g.

mkoctfile -p CFLAGS

to get the libs, compiler flags etc. Have a look at the manpage for this.

Comments