| 48 | A ConduitExit is used for receiving in a blocking mode. There are two receive methods: receive() and receiveObservation(). In the first case only the data is received. In the second, an observation is received, which contains the data but also the timestamp at which the data was sent, and the timestamp at which the next message will arrive. So, |
| 49 | {{{ |
| 50 | double[] dataA = exitA.receive(); |
| 51 | }}} |
| 52 | or |
| 53 | {{{ |
| 54 | Observation<double[]> obsA = exitA.receiveObservation(); |
| 55 | double[] dataA = obsA.getData(); |
| 56 | Timestamp time = obsA.getTimestamp(); |
| 57 | }}} |
| 58 | |
| 59 | A ConduitEntrance has several different send functions. The most basic send(data) sends the data and deduces the timestamp at which the data is sent, by adding delta T of the timescale to the previous timestamp. If the instance is dimensionless, or if required, you can explicitly set the timestamp of the data, and the timestamp at which you send the next message with send(data, time, nextTime): |
| 60 | {{{ |
| 61 | Timestamp time = Timestamp.ZERO; |
| 62 | Timestamp nextTime = new Timestamp(2.0); |
| 63 | entranceA.send(data, time, nextTime); |
| 64 | }}} |
| 65 | Finally, a muscle.core.model.Observation object can also be sent and it contains the same information: data, a time and the next time. |
| 66 | {{{ |
| 67 | Observation<double[]> obs = new Observation<double[]>(data, time, nextTime); |
| 68 | entranceA.send(obs); |
| 69 | }}} |
| 70 | |
| 71 | Although the entrance is automatically closed once the instance is finished, it is also possible to close the conduit earlier. |
| 72 | |
| 95 | |
| 96 | === Submodels === |
| 97 | |
| 98 | In MML, submodels are governed by a Submodel Execution Loop. Interpreting this for MUSCLE, this looks like: |
| 99 | {{{ |
| 100 | while (true) { |
| 101 | state, timeOrigin = init(t0) // we are allowed to receive messages |
| 102 | while not endCondition() { |
| 103 | intermediateObservation() // we are allowed to send messages |
| 104 | state = solvingStep() // we are allowed to receive messages |
| 105 | } |
| 106 | finalObservation() // we are allowed to send messages |
| 107 | if not restartSubmodel() { |
| 108 | break |
| 109 | } |
| 110 | } |
| 111 | }}} |
| 112 | Step by step, a submodel can be restarted any number of times depending on the couplings, this is what the outer loop does. Next, each time a submodel is run, it has an initialization phase where it determines the initial state and what the simulation time of this initial state should be. Then it enters a while loop while some end condition is not met. Each iteration it sends some observation of the state, and it computes the next state. When the end condition is met, it is possible to do some cleaning and to send a final observation. At the end of the submodel it decides whether it should restart. |
| 113 | |
| 114 | In MUSCLE, endCondition is implemented as the willStop() method, which looks at all the messages sent and received and the message with the highest simulation time is compared with the total time in the timescale of the submodel, with parameter "submodelName:T". |