Multiple models and parallel solving with mmjobs
The module mmjobs makes it possible to exchange information between models running concurrently—locally or in a network. Its functionality includes facilities for handling Mosel instances (e.g. connecting and disconnecting Mosel instances, access to remote files), model management (e.g. compiling, running, or interrupting a model from within a second model), synchronization of concurrent models based on event queues, and a shared memory I/O driver for an efficient exchange of data between models that are executed concurrently.
Several complete examples (including examples of Benders decomposition and Dantzig-Wolfe decomposition) of the use of module mmjobs are described in the whitepaper Multiple models and parallel solving with Mosel that is provided as a part of the Xpress documentation and also on the 'Product Documentation' page of the Xpress website. We show here how to use the basic functionality for executing a model from a second model.
Running a model from another model
As a test case, we shall once more work with model prime.mos from Section Working with sets. In the first instance, we now show how to compile and run this model from a second model, runprime.mos:
model "Run model prime" uses "mmjobs" declarations modPrime: Model event: Event end-declarations ! Compile 'prime.mos' if compile("prime.mos")<>0 then exit(1); end-if load(modPrime, "prime.bim") ! Load bim file run(modPrime, "LIMIT=50000") ! Start execution and wait(2) ! wait 2 seconds for an event if isqueueempty then ! No event has been sent... writeln("Model too slow: stopping it!") stop(modPrime) ! ... stop the model, wait ! ... and wait for the termination event end-if ! An event is available: model finished event:=getnextevent writeln("Exit status: ", getvalue(event)) writeln("Exit code : ", getexitcode(modPrime)) unload(modPrime) ! Unload the submodel end-model
The compile command generates the BIM file for the given submodel; the command load loads the binary file into Mosel; and finally we start the model with the command run. The run command is not used in its basic version (single argument with the model reference): here its second argument sets a new value for the parameter LIMIT of the submodel.
In addition to the standard compile–load–run sequence, the model above shows some basic features of interaction with the submodel: if the submodel has not terminated after 2 seconds (that is, if it has not sent a termination message) it is stopped by the master model. After termination of the submodel (either by finishing its calculations within less than 2 seconds or stopped by the master model) its termination status and the exit value are retrieved (functions getvalue and getexitcode). Unloading a submodel explicitly as shown here is only really necessary in larger applications that continue after the termination of the submodel, so as to free the memory used by it.
Note: our example model shows an important property of submodels—they are running in parallel to the master model and also to any other submodels that may have been started from the master model. It is therefore essential to insert wait at appropriate places to coordinate the execution of the different models.
Compiling to memory
The model shown in the previous section compiles and runs a submodel. The default compilation of a Mosel file filename.mos generates a binary model file filename.bim. To avoid the generation of physical BIM files for submodels we may compile the submodel to memory, making use of the concept of I/O drivers introduced in Section Generalized file handling.
Compiling a submodel to memory is done by replacing the standard compile and load commands by the following lines (model runprime2.mos):
if compile("","prime.mos","shmem:bim")<>0 then exit(1) end-if load(modPrime,"shmem:bim") ! Load bim file from memory... fdelete("shmem:bim") ! ... and release the memory block
The full version of compile takes three arguments: the compilation flags (e.g., use "g" for debugging), the model file name, and the output file name (here a label prefixed by the name of the shared memory driver). Having loaded the model we may free the memory used by the compiled model with a call to fdelete (this subroutine is provided by the module mmsystem).
Exchanging data between models
When working with submodels we are usually not just interested in executing the submodels, we also wish to retrieve their results in the master model. This is done most efficiently by exchanging data in (shared) memory as shown in the model runprimeio.mos below. Besides the retrieval and printout of the solution we have replaced the call to stop by sending the user event `STOPMOD' to the submodel: instead of simply terminating the submodel this event will make it interrupt its calculations and write out the current solution. To make sure that the submodel is actually running at the point where we sent the `STOPMOD' event, we have also introduced an event sent from the submodel to the master to indicate the point of time when it starts the calculations (with heavy operating system loads the actual submodel start may be delayed). Once the submodel has terminated (after sending the `STOPMOD' event we wait for the model's termination message) we may read its solution from memory, using the initializations block with the drivers raw (binary format) and shmem (read from shared memory).
model "Run model primeio" uses "mmjobs" declarations modPrime: Model NumP: integer ! Number of prime numbers found SetP: set of integer ! Set of prime numbers STOPMOD = 2 ! "Stop submodel" user event MODREADY = 3 ! "Submodel ready" user event end-declarations ! Compile 'prime.mos' if compile("primeio.mos")<>0 then exit(1); end-if load(modPrime, "primeio.bim") ! Load bim file ! Disable model output setdefstream(modPrime,"","null:","null:") run(modPrime, "LIMIT=35000") ! Start execution and wait ! ... wait for an event if getclass(getnextevent) <> MODREADY then writeln("Problem with submodel run") exit(1) end-if wait(2) ! Let the submodel run for 2 seconds if isqueueempty then ! No event has been sent... writeln("Model too slow: stopping it!") send(modPrime, STOPMOD, 0) ! ... stop the model, then wait wait end-if dropnextevent ! Discard end events initializations from "bin:shmem:resdata" NumP SetP as "SPrime" end-initializations writeln(SetP) ! Output the result writeln(" (", NumP, " prime numbers.)") unload(modPrime) end-model
We now have to modify the submodel (file primeio.mos) correspondingly: at its start it sends the `MODREADY' event to trigger the start of the time measurement in the master and it further needs to intercept the `STOPMOD' event interrupting the calculations (via an additional test isqueueempty for the repeat-until loop) and write out the solution to memory in the end:
model "Prime IO" uses "mmjobs" parameters LIMIT=100 ! Search for prime numbers in 2..LIMIT OUTPUTFILE = "bin:shmem:resdata" ! Location for output data end-parameters declarations SNumbers: set of integer ! Set of numbers to be checked SPrime: set of integer ! Set of prime numbers MODREADY = 3 ! "Submodel ready" user event end-declarations send(MODREADY,0) ! Send "model ready" event SNumbers:={2..LIMIT} writeln("Prime numbers between 2 and ", LIMIT, ":") n:=2 repeat while (not(n in SNumbers)) n+=1 SPrime += {n} ! n is a prime number i:=n while (i<=LIMIT) do ! Remove n and all its multiples SNumbers-= {i} i+=n end-do until (SNumbers={} or not isqueueempty) NumP:= getsize(SPrime) initializations to OUTPUTFILE NumP SPrime end-initializations end-model
Note: since the condition isqueueempty is tested only once per iteration of the repeat-until loop, the termination of the submodel is not immediate for large values of LIMIT. If you wish to run this model with very large values, please see Section Efficient modeling through the Mosel Profiler for an improved implementation of the prime number algorithm that considerably reduces its execution time.
Distributed computing
The module mmjobs not only allows the user to start several models in parallel on a given machine, it also makes it possible to execute models remotely and to coordinate their processing. With only few additions, the model from Section Running a model from another model is extended to form model version runprimedistr.mos that launches the submodel prime.mos on another Mosel instance (either on the local machine as in the present example or on some other machine within a network specified by its name or IP address in the connect statement): we need to create a new Mosel instance (through a call to connect) and add an additional argument to the load statement to specify the Mosel instance we wish to use. All else remains the same as in the single-instance version.
model "Run model prime remotely" uses "mmjobs" declarations moselInst: Mosel modPrime: Model event: Event end-declarations ! Compile 'prime.mos' locally if compile("prime.mos")<>0 then exit(1); end-if ! Start a remote Mosel instance: ! "" means the node running this model if connect(moselInst, "")<>0 then exit(2); end-if ! Load bim file into remote instance load(moselInst, modPrime, "rmt:prime.bim") run(modPrime, "LIMIT=50000") ! Start execution and wait(2) ! wait 2 seconds for an event if isqueueempty then ! No event has been sent... writeln("Model too slow: stopping it!") stop(modPrime) ! ... stop the model, then wait wait end-if ! An event is available: model finished event:=getnextevent writeln("Exit status: ", getvalue(event)) writeln("Exit code : ", getexitcode(modPrime)) unload(modPrime) ! Unload the submodel end-model
This model can be extended to include data exchange between the master and the submodel exactly in the same way as in the example of Section Exchanging data between models. The main difference (besides the connection to a remote instance) lies in the use of the driver rmt to denote the Mosel instance where data is to be saved. In our case, we wish to save data on the instance running the master model, meaning that we need to use the rmt: prefix when writing output within the submodel. The new output file name is passed into the submodel via the runtime parameter OUTPUTFILE:
run(modPrime, "LIMIT=35000,OUTPUTFILE=bin:rmt:shmem:resdata")
The master model then simply reads as before from its own instance:
initializations from "bin:shmem:resdata" NumP SetP as "SPrime" end-initializations
The Mosel model for the extended version including data exchange is provided in the file runprimeiodistr.mos.
© 2001-2020 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.