Initializing help system before first use

# Exchange of information with embedded models

Topics covered in this section:

- mem: working in memory
  - Java version of the example
  - .NET version of the example
  - mmjobs version of the example
- raw: binary data format of the host application
  - Java version of the example
  - .NET version of the example
  - mmjobs version of the example
- cb: output to callback functions
  - Java version of the example
  - .NET version of the example
- sysfd: working with system file descriptors
  - Java version of the example
  - .NET version of the example

In this section we show several examples of the use of I/O drivers in the Mosel distribution. The full documentation of these drivers is contained in the `Mosel Libraries Reference Manual'. When exchanging data between a Mosel model and a host application, the employed data structures need to match the representation of data in the particular host language and the choice of communication mechanisms (e.g., memory blocks, streams) depends on the functionality available in this language. Each Mosel library interface therefore provides its own I/O drivers, presented as subsections to the following examples that are organized around the functionality provided by Mosel's C libraries.

## mem: working in memory

The mem I/O driver makes it possible to use a block of memory as a data source. The following example shows how to use this driver to compile a Mosel model to memory (instead of creating a physical BIM file). This means that the resulting application does not generate any auxiliary file for handling the model. This feature may be of interest especially in distributed systems.

In the code printed below and in all subsequent examples the error handling is omitted for clarity's sake. The full examples are on the Xpress website.

    #include <stdio.h>
    #include "xprm_mc.h"

    int main()
    {
     XPRMmodel mod;
     int result;
     char bimfile[2000];              /* Buffer to store BIM file */
     size_t bimfile_size;             /* Buffer to store actual size of BIM file */
     char bimfile_name[64];           /* File name of BIM file */

     XPRMinit();                      /* Initialize Mosel */

    /* Prepare file name for compilation using 'mem' driver: */
    /*   "mem:base address/size[/actual size pointer]"       */
     bimfile_size=0;
     sprintf(bimfile_name, "mem:%p/%d/%p",
             bimfile, (int)sizeof(bimfile), &bimfile_size);

                                      /* Compile model file to memory */
     XPRMcompmod(NULL, "burglar2.mos", bimfile_name, "Knapsack example");
     printf("BIM file uses %lu bytes of memory.\n", bimfile_size);

                                      /* Load the BIM file from memory */
     mod=XPRMloadmod(bimfile_name, NULL);

     XPRMrunmod(mod, &result, NULL);  /* Run the model */

     return 0;
    }

The only change to standard use of the Mosel library functions is the replacement of the (physical) BIM file by an extended filename in function XPRMcompmod. The extended filename indicates the driver we want to use (mem), an address where to store the BIM file, and the space reserved for it. Notice that the size of the resulting BIM file is not known before compilation. In this example we reserve roughly twice the size of the model file for the BIM file. However, there is no guarantee that this is sufficient for other models. We therefore print out the size of the generated file as a control.

We may take working in memory one step further, by including the source of the Mosel model directly in the C source code. After compilation, we obtain a single all-in-one application file that does not require or generate any auxiliary file for handling the model.

The source of the model is included in the C source file as an array of characters:

    const char source_of_model[]=
    "model Burglar\n"
    "uses 'mmxprs'\n"

    "declarations\n"
    " WTMAX = 102                    ! Maximum weight allowed\n"
    " ITEMS = {'camera', 'necklace', 'vase', 'picture', 'tv', 'video', \n"
    "          'chest', 'brick'}     ! Index set for items\n"
    " VALUE: array(ITEMS) of real    ! Value of items\n"
    " WEIGHT: array(ITEMS) of real   ! Weight of items\n"
    " take: array(ITEMS) of mpvar    ! 1 if we take item i; 0 otherwise\n"
    "end-declarations\n"

    "VALUE::(['camera', 'necklace', 'vase', 'picture', 'tv', 'video',\n"
    "         'chest', 'brick'])[15,100,90,60,40,15,10,1]\n"
    "WEIGHT::(['camera', 'necklace', 'vase', 'picture', 'tv', 'video',\n"
    "          'chest', 'brick'])[2,20,20,30,40,30,60,10]\n"

    "! Objective: maximize total value\n"
    "MaxVal:= sum(i in ITEMS) VALUE(i)*take(i)\n"

    "! Weight restriction\n"
    "sum(i in ITEMS) WEIGHT(i)*take(i) <= WTMAX\n"
    "! All variables are 0/1\n"
    "forall(i in ITEMS) take(i) is_binary\n"

    "maximize(MaxVal)                ! Solve the problem\n"

    "! Print out the solution\n"
    "writeln(\"Solution:\\n Objective: \", getobjval)\n"
    "forall(i in ITEMS)  writeln(' take(', i, '): ', getsol(take(i)))\n"

    "end-model";

In the compilation command we replace the filename burglar2.mos by an extended filename, consisting in the driver to be used (mem) and the address and size of the model source.

     char mosfile_name[40];           /* File name of MOS file */

     sprintf(mosfile_name, "mem:%p/%d",
             source_of_model, (int)sizeof(source_of_model));

                                      /* Compile model from memory to memory */
     XPRMcompmod(NULL, mosfile_name, bimfile_name, "Knapsack example");

The data in this Mosel model are hardcoded directly in the model. In the following section we show how to extend this example with data input from memory, using the raw driver.

#### Java version of the example

The Java implementation of the model version compiling a Mosel model held in memory to a BIM file that is equally stored in memory uses objects of type ByteBuffer to communicate with Mosel.

    // The source of the model as a string
     static final String source_of_model=
      "model Burglar\n"+
      "uses 'mmxprs'\n"+
    ...
      "end-model";

     public static void main(String[] args) throws Exception
     {
      XPRM mosel;
      XPRMModel mod;
      ByteBuffer mosfile;                   // Buffer to store source file
      ByteBuffer bimfile;                   // Buffer to store BIM file

      mosel = new XPRM();                   // Initialize Mosel

                                            // Prepare file names for compilation:
                                            // Wrap source in a byte buffer
      mosfile=ByteBuffer.wrap(source_of_model.getBytes());
      bimfile=ByteBuffer.allocateDirect(2048);     // Create a 2K byte buffer
      mosel.bind("mybim", bimfile);         // Associate Java object
      mosel.bind("modelfile", mosfile);     // with a name in Mosel

      try
      {                                     // Compile model from memory to memory
       mosel.compile("", "java:modelfile", "java:mybim", "");
      }
      catch(XPRMCompileException e)
      {
       System.out.println(e.getMessage());
      }
      mosel.unbind("mosfile");              // Release memory
      mosfile=null;

      bimfile.limit(bimfile.position());    // Mark end of data in the buffer
      bimfile.rewind();                     // Back to the beginning
      System.out.println("BIM file uses "+bimfile.limit()+" bytes of memory.");

      mod=mosel.loadModel("java:mybim");    // Load BIM file from memory
      mosel.unbind("mybim");                // Release memory
      bimfile=null;

      mod.run();                            // Run the model
     }

#### .NET version of the example

The .NET interface defines a combined compile+load method that keeps a temporary BIM file in memory. We can therefore simply write the following program to compile a Mosel model from and to memory.

    // String containing the model
     const string modelSource=
        "model Burglar\n"+
        "uses 'mmxprs'\n"+
    ...
        "end-model";

    // Main entry point for the application
     static void Main(string[] args) {
      // Initialize Mosel
      XPRM mosel = XPRM.Init();

      // Compile and load the Mosel model
      XPRMModel model = mosel.CompileAndLoad(new StringReader(modelSource));

      // Run the model
      model.Run();
     }

If however, we explicitly wish to create a physical BIM file we can use the separate Compile and LoadModel methods:

     static void Main(string[] args) {
      // Initialize Mosel
      XPRM mosel = XPRM.Init();

      // Compile the Mosel model to a physical file
      FileStream file= new FileStream("burglar2.bim", FileMode.Create, FileAccess.Write);
      mosel.Compile("", new StringReader(modelSource), file);
      file.Close();

      // Load the Mosel model
      XPRMModel model = mosel.LoadModel("burglar2.bim");

      // Run the model
      model.Run();
     }

#### mmjobs version of the example

An alternative form of 'embedding' a Mosel model is running a (sub)model from another Mosel model (the parent or main model). The functionality for managing and coordinating multiple models is provided by the module mmjobs (documented in the chapter `mmjobs' of the `Mosel Language Reference Manual'). The reader is referred to the Mosel whitepaper `Multiple models and parallel solving with Mosel' for a comprehensive set of examples. With mmjobs we use the driver shmem for saving data in shared memory (memory accessible to models running in the same Mosel instance).

    model "Run model burglar"
     uses "mmjobs"

     declarations
      modBurg: Model                     ! Submodel
     end-declarations
                                         ! Compile the model, save bim in memory
     if compile("", "burglar2.mos", "shmem:burglar2.bim")<>0 then exit(1); end-if
     load(modBurg, "shmem:burglar2.bim") ! Load the bim file
     run(modBurg)                        ! Start model execution
     wait                                ! Wait for model termination
     dropnextevent                       ! Ignore termination event message

    end-model

## raw: binary data format of the host application

The raw I/O driver provides an implementation of the initializations block in binary mode: instead of translating information from/to text format, data is kept in its raw representation. The following example shows how to use this driver in combination with the mem driver to exchange arrays of data between a model and an application through memory. As shown in the previous section, we may work with a separate model file (this example) or alternatively include the model source directly in the model.

    #include <stdio.h>
    #include "xprm_mc.h"

    const struct
    {                                 /* Initial values for array 'data': */
     const char *ind;                 /*   index name */
     double val,wght;                 /*   value and weight data entries */
    } data[]={{"camera",15,2}, {"necklace",100,20}, {"vase",90,20},
              {"picture",60,30}, {"tv",40,40}, {"video",15,30},
              {"chest",10,60}, {"brick",1,10}};

    double solution[8];               /* Array for solution values */

    int main()
    {
     XPRMmodel mod;
     int result;
     XPRMalltypes rvalue, itemname;
     XPRMset set;
     char bimfile[2000];              /* Buffer to store BIM file */
     size_t bimfile_size;             /* Buffer to store actual size of BIM file */
     char bimfile_name[64];           /* File name of BIM file */
     char data_name[40];              /* File name of initial values for 'data' */
     char solution_name[40];          /* File name of solution values */
     char params[96];                 /* Parameter string for model execution */

     XPRMinit();                      /* Initialize Mosel */

    /* Prepare file name for compilation using 'mem' driver: */
    /*   "mem:base address/size[/actual size pointer]"       */
     bimfile_size=0;
     sprintf(bimfile_name, "mem:%p/%d/%p",
             bimfile, (int)sizeof(bimfile), &bimfile_size);

                                      /* Compile model file to memory */
     XPRMcompmod(NULL, "burglar2r.mos", bimfile_name, "Knapsack example");
     printf("BIM file uses %lu bytes of memory.\n", bimfile_size);

                                      /* Load a BIM file from memory */
     mod=XPRMloadmod(bimfile_name, NULL);

    /* Prepare file names for 'initializations' using the 'raw' driver:         */
    /*   "rawoption[,...],filename"                                             */
    /*   (Here, 'filename' uses the 'mem' driver, data is stored in memory)     */
    /* Options for 'raw':                                                       */
    /* 'slength=0': strings are represented by  pointers to null terminated     */
    /*              arrays of characters (C-string) instead of fixed size arrays*/
    /* 'noindex':   only array values are expected - no indices requested       */

     sprintf(data_name, "slength=0,mem:%p/%d", data, (int)sizeof(data));
     sprintf(solution_name, "noindex,mem:%p/%d", solution, (int)sizeof(solution));

                                      /* Pass file names as execution param.s */
     sprintf(params, "DATA='%s',SOL='%s'", data_name, solution_name);

     XPRMrunmod(mod, &result, params);   /* Run the model */

    /* Display solutions values obtained from the model */
     printf("Objective: %g\n", XPRMgetobjval(mod));
     XPRMfindident(mod, "ITEMS", &rvalue);     /* Get the model object 'ITEMS' */
     set = rvalue.set;
     for(i=0;i<8;i++)
      printf(" take(%s): %g\n", XPRMgetelsetval(set, i+1, &itemname)->string,
             solution[i]);

     return 0;
    }

The input data in the C code above is stored and communicated to the model in sparse format, that is, each data item with its index tuple. For retrieving and saving the solution data this example uses dense format, that is, just the data items without explicitly specifying the indices. To obtain a printout with the (string) index names, we retrieve separately the set of indices from the Mosel model. Alternatively, we could also use sparse format for the solution data similarly to the input data, in which case we did not have to retrieve the index set separately.

The model file burglar2r.mos of this example is very similar to the model versions for the odbc and diskdata I/O drivers in Section Data source access from Mosel models. The only changes made are to the name of the I/O driver and to the strings DATA and SOL for the data source and the destination of results respectively. Furthermore, the set ITEMS that is accessed from the C program needs to be declared as public.

    model Burglar2r
     uses 'mmxprs'

     parameters
      IODRV = 'raw:'
      DATA=''
      SOL=''
      WTMAX = 102                    ! Maximum weight allowed
     end-parameters

     declarations
      public ITEMS: set of string    ! Index set for items
      VALUE: array(ITEMS) of real    ! Value of items
      WEIGHT: array(ITEMS) of real   ! Weight of items
      SOLTAKE: array(ITEMS) of real  ! Solution values
     end-declarations

     initialisations from IODRV
      [VALUE,WEIGHT] as DATA
     end-initialisations

     declarations
      take: array(ITEMS) of mpvar    ! 1 if we take item i; 0 otherwise
     end-declarations

    ! Objective: maximize total value
     MaxVal:= sum(i in ITEMS) VALUE(i)*take(i)

    ! Weight restriction
     sum(i in ITEMS) WEIGHT(i)*take(i) <= WTMAX

    ! All variables are 0/1
     forall(i in ITEMS) take(i) is_binary

     maximize(MaxVal)                ! Solve the problem

    ! Solution output
     forall(i in ITEMS) SOLTAKE(i):= getsol(take(i))

     initialisations to IODRV
      SOLTAKE as SOL
     end-initialisations

    end-model

The example above uses sparse data format, that is, every data entry comprises its index (or index tuple) and the actual value (or list of values in our case). A model version using dense data format, so communicating just the data values without the indices, is described in Chapter 13.4.1 `Exchanging data between an application and a modelDense arrays' of the `Mosel User Guide'.

The raw format communicates data via fixed-size memory blocks. Greater flexibility through dynamic sizing of the data structures can be achieved by using the callback functionality provided through the driver cb (see Section cb: output to callback functions below and the examples of Chapters 13.4.3 and 14.1.7.3 `Exchanging data between an application and a model Dynamic data' of the `Mosel User Guide' for C and Java examples respectively).

#### Java version of the example

With the Mosel Java libraries, we replace the C driver raw by the Java binary format I/O driver jraw. Just as in the C version, we have stored the model data in a single structure containing the string index and the two data values for 'weight' and 'value' of every item. Mosel returns the solution into a second structure that also stores index and data values.

    // Class to store initial values for array 'data'
     public static class MyData
     {
      public String ind;                // index name
      public double val,wght;           // value and weight data entries
      MyData(String i, double v, double w)
      { ind=i; val=v; wght=w; }
     }
                            // Class to receive solution values
     public static class MySol
     {
      public String ind;                // index name
      public double val;                // solution value
     }

     public static void main(String[] args) throws Exception
     {
      XPRM mosel;
      XPRMModel mod;
      MyData data[]={new MyData("camera",15,2), new MyData("necklace",100,20),
                     new MyData("vase",90,20), new MyData("picture",60,30),
    		 new MyData("tv",40,40), new MyData("video",15,30),
                     new MyData("chest",10,60), new MyData("brick",1,10)};
      MySol[] solution=new MySol[8];

      for(int i=0;i<8;i++) solution[i] = new MySol();

      mosel = new XPRM();                 // Initialize Mosel

      mosel.compile("burglar2r.mos");     // Compile & load the model
      mod = mosel.loadModel("burglar2r.bim");

                            // Associate the Java objects with names in Mosel
      mosel.bind("dt", data);
      mosel.bind("sol", solution);
                            // File names are passed through execution parameters
      mod.execParams = "DATA='dt(ind,val,wght)',SOL='sol(ind,val)',IODRV='jraw:'";

      mod.run();                          // Run the model

      if(mod.getProblemStatus()!=mod.PB_OPTIMAL)
       System.exit(1);                    // Stop if no solution found

                            // Display solution values obtained from the model
      System.out.println("Objective value: " + mod.getObjectiveValue());
      for(int i=0;i<8;i++)
       System.out.println(" take(" + solution[i].ind + "): " + solution[i].val);

      mod.close();                        // Unload the model
     }

A model version using dense data format is discussed in Chapter 14.1.7.1 `Exchanging data between an application and a modelDense arrays' of the `Mosel User Guide'.

#### .NET version of the example

The .NET version of our program is again very similar to its Java version. We now use the I/O driver dotnetraw in the place of jraw.

    // Arrays containing initialization data for the model
     static double[] vdata = new double[] {15,100,90,60,40,15,10, 1};  // VALUE
     static double[] wdata = new double[] { 2, 20,20,30,40,30,60,10};  // WEIGHT

     // Structure to store initial values for the array 'data'
     class MyData {
      public string ind;
      public double val;
      public double wght;

      public MyData(string i, double v, double w) {
       this.ind = i;
       this.val = v;
       this.wght = w;
      }
     }

    // Structure to receive solution values
     class MySol {
      public string ind;
      public double val;
     }

    // The initial values for the array 'data'
     private static MyData[] data = new MyData[] {
                     new MyData("camera",15,2), new MyData("necklace",100,20),
                     new MyData("vase",90,20), new MyData("picture",60,30),
    		 new MyData("tv",40,40), new MyData("video",15,30),
                     new MyData("chest",10,60), new MyData("brick",1,10) };

    // Main entry point for the application
     static void Main(string[] args) {
      // Initialize Mosel
      XPRM mosel = XPRM.Init();

      // Compile and load the Mosel model
      XPRMModel model = mosel.CompileAndLoad("burglar2r.mos");

      // Associate the .NET object with a name in Mosel
      model.Bind("dt", data);

      // Create a new array for solution data and bind that to the name 'SOL'
      MySol[] solution=new MySol[8];
      for(int i=0;i<8;i++) solution[i] = new MySol();
      mosel.Bind("sol", solution);

      // Pass data location as a parameter to the model
      model.ExecParams =
          "DATA='dt(ind,val,wght)',SOL='sol(ind,val)',IODRV='dotnetraw:'";

      // Run the model
      model.Run();

      // Print the solution
      Console.WriteLine("Objective value: {0}", model.ObjectiveValue);
      for(int i=0;i<8;i++)
       Console.Write(" take({0}): {1}",  solution[i].ind, solution[i].val);
      Console.WriteLine();
     }

#### mmjobs version of the example

When running a Mosel model from another model, the two models can exchange data in memory using the binary format defined by raw. Given the restrictions of the raw format (each 'file' only contains a single data array, composite Mosel data structures are not supported) we recommend however to give preference to the more flexible binary format defined by the bin driver that supports the full set of data structures of initializations blocks (see Section bin: using Mosel's binary format below). Here is an example of a Mosel model reading and writing data to memory in binary format using bin.

    model "Run model burglar IO"
     uses "mmjobs"

     declarations
      modBurg: Model                    ! Submodel
      ISet,SSet: set of string          ! Index set for data arrays
      V,W: array(ISet) of real          ! Data arrays
      Solution: array(SSet) of real     ! Solution values
     end-declarations

     V:: (["camera","necklace","vase","picture","tv","video","chest","brick"])
          [15, 100, 90, 60, 40, 15, 10,  1]
     W:: (["camera","necklace","vase","picture","tv","video","chest","brick"])
          [ 2,  20, 20, 30, 40, 30, 60, 10]

                                        ! Compile the model, save bim in memory
     if compile("burglar2r.mos")<>0 then exit(1); end-if
     load(modBurg, "burglar2r.bim")     ! Load the bim file

     setdefstream(modBurg, F_OUTPUT, "null:")   ! Disable output from submodel

    ! Save data in shared memory
     IODRV:="bin:shmem:burgdata"
     initializations to IODRV
      [V,W] as "Burgdata"
     end-initializations
                                        ! Start model execution, setting parameters
     run(modBurg, "IODRV='" +IODRV + "',DATA='Burgdata',SOL='Solution'")
     wait                               ! Wait for model termination
     dropnextevent                      ! Ignore termination event message

    ! Retrieve solution from shared memory
     initializations from IODRV
      Solution
     end-initializations

     forall(i in SSet)  writeln(" take(", i, "): ", Solution(i))

    end-model

The relevant part of the model above look as follows with the raw I/O driver.

    ! Save data in shared memory
     IODRV:="raw:"
     initializations to IODRV
      [V,W] as "shmem:Burgdata"
     end-initializations
                                        ! Start model execution, setting parameters
     run(modBurg, "IODRV='" +IODRV + "',DATA='shmem:Burgdata',SOL='shmem:SolTake'")
     wait                               ! Wait for model termination
     dropnextevent                      ! Ignore termination event message

    ! Retrieve solution from shared memory
     initializations from IODRV
      Solution as "shmem:SolTake"
     end-initializations

## cb: output to callback functions

Using the cb I/O driver a function is used as a file. Depending on the type of stream to manage (i.e. a general stream or a stream for an initializations block) a specific function type has to be provided. In the following example we define a callback function to receive the output stream. Our function simply prints all output lines preceeded by Mosel: .

    #include <stdio.h>
    #include "xprm_mc.h"

    /* Callback function to handle output */
    long XPRM_RTC cbmsg(XPRMmodel model, void *info, char *buf, unsigned long size)
    {
    /* Note: 'model' is NULL if the stream is used outside of an execution */
     printf("Mosel: %.*s", (int)size, buf);
     return 0;
    }

    int main()
    {
     XPRMmodel mod;
     int result;
     char outfile_name[40];           /* File name of output stream */

     XPRMinit();                      /* Initialize Mosel */

                                      /* Prepare file name for output stream   */
                                      /* using 'cb' driver:                    */
                                      /* "cb:function pointer[/callback data]" */
     sprintf(outfile_name, "cb:%p", cbmsg);

                                      /* Set default output stream to callback */
     XPRMsetdefstream(NULL, XPRM_F_WRITE, outfile_name);

                                      /* Execute = compile/load/run model file
                                                   `burglar2.mos'
                                         Generates the BIM file `burglar2.bim' */
     XPRMexecmod(NULL, "burglar2.mos", NULL, &result, NULL);

     return 0;
    }

The output produced by this program looks as follows:

    Mosel: Solution:
    Mosel:  Objective: 280
    Mosel: [(`camera',1),(`necklace',1),(`vase',1),(`picture',1),(`tv',0),
    (`video',1),(`chest',0),(`brick',0)]

Callback functionality can also be used for data I/O in initializations blocks—see Chapters 13.4.3 and 14.1.7.3 (Exchanging data between an application and a model – Dynamic data) of the `Mosel User Guide' for C and Java examples respectively.

#### Java version of the example

The stream redirections functions of the Mosel Java library expect objects of the type InputStream or OutputStream. The following Java program implements the same behavior as the C program above. With Java, we replace the cb driver by the Java memory driver java.

    // OutputStream class to handle default output
     public static class MyOut extends OutputStream
     {
      public void flush()
      { System.out.flush(); }
      public void write(byte[] b)
      {
       System.out.print("Mosel: ");
       System.out.write(b, 0, b.length);
      }
      // The following methods are not used by Mosel:
      public void write(byte[] b, int off, int len) {}
      public void write(int b) {}
      public void close() {}
     }

     public static void main(String[] args) throws Exception
     {
      XPRM mosel;
      XPRMModel mod;
      MyOut cbmsg = new MyOut();            // Define output stream as "MyOut"

      mosel = new XPRM();                   // Initialize Mosel

      mosel.bind("mycb", cbmsg);    // Associate Java object with a name in Mosel
                                    // Set default output stream to cbmsg
      mosel.setDefaultStream(XPRM.F_OUTPUT|XPRM.F_LINBUF, "java:mycb");

      mosel.compile("burglar2.mos");        // Compile, load & run the model
      mod = mosel.loadModel("burglar2.bim");
      mod.run();
     }

#### .NET version of the example

With the Mosel .NET libraries, the stream redirection functions accept the objects TextWriter and TextReader in addition to strings with Mosel file names. We therefore have several different implementation options for our example.

The following version of our example closely matches the structure of the Java program from the previous section—it makes use of the dotnet I/O driver for redirecting the model output to a custom TextWriter object:

     static void Main(string[] args) {
      // Initialize Mosel
      XPRM mosel = XPRM.Init();

      // Associate .NET object with a name in Mosel
      mosel.Bind("mycb", new MyOut());

      // Compile and load the Mosel model
      XPRMModel model = mosel.CompileAndLoad("burglar2.mos");

      // Redirect the model's output to our printing function 'cbmsg'
      model.SetDefaultStream(XPRMStreamType.F_OUTPUT_LINEBUF, "dotnet:mycb");

      // Run the model
      model.Run();
     }

Alternatively, we can simply use this form of our program (without employing any I/O driver):

     static void Main(string[] args) {
      // Initialize Mosel
      XPRM mosel = XPRM.Init();

      // Compile and load the Mosel model
      XPRMModel model = mosel.CompileAndLoad("burglar2.mos");

      // Redirect the model's output to a custom TextWriter
      MyOut modelOut = new MyOut();
      model.SetDefaultStream(XPRMStreamType.F_OUTPUT_LINEBUF, modelOut);

      // Run the model
      model.Run();
     }

In both cases, we work with the following definition for the class MyOut:

     public class MyOut: TextWriter
     {
      private bool atStartOfLine = true;
      public override void Write(char b)
      {
        if (atStartOfLine) {
         Console.Write("Mosel: ");
         atStartOfLine=false;
        }
        if (b=='\n') {
         Console.WriteLine();
         atStartOfLine=true;
        }
        else if (b=='\r') {
         // ignore
        }
        else {
         Console.Write(b);
        }
      }
      public override Encoding Encoding {
       get {
        return Encoding.UTF8;
       }
      }
     }

## sysfd: working with system file descriptors

With the sysfd driver a file descriptor provided by the operating system can be used in place of a file. File descriptors are returned by the C functions open or fileno. They also include the default input, output, and error streams (values 0, 1, and 2 respectively) that are opened automatically when a program starts. For instance, to redirect the error stream for a model mod to the default output we may write:

    XPRMsetdefstream(mod, XPRM_F_ERROR, "sysfd:1");

#### Java version of the example

In Java, we use the driver java to indicate redirection to a system stream.

     mod.setDefaultStream(XPRM.F_ERROR, "java:java.lang.System.out");

#### .NET version of the example

With .NET we can immediately specify an output location, such as

    model.SetDefaultStream(XPRMStreamType.F_ERROR, Console.Out);

Parent Topic Mosel IO Whitepaper

© 2001-2026 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.