[MBDyn-users] Exact MBCNodal calling sequence

Pierangelo Masarati pierangelo.masarati at polimi.it
Wed Mar 15 19:44:29 CET 2017

On 03/14/2017 10:55 PM, Richard Crozier wrote:
> On 13/03/17 21:07, Pierangelo Masarati wrote:
>> On 03/13/2017 06:20 PM, Richard Crozier wrote:
>>> I'm hoping I can get some help understanding the exact sequence of
>>> events when using the MBCNodal C++ class to use libmbc to communicate
>>> with mbdyn as I can't quite figure it out from the manual or code
>>> comments. I'm interested in both the loose and tight options, but
>>> starting with loose.
>>> In the case of loose coupling the manual states the following:
>>> 1. MBDyn sends a set of kinematic parameters related to step k after
>>> predict.
>>> 2. MBDyn receives a set of forces sent by the external peer the first
>>> time the residual is assembled within time step k; the external peer
>>> generated that set of forces based on the predicted kinematics
>>> at step k;
>>> In this case how exactly would I actually implement this sequence in
>>> terms of calls to MBCNodal.GetMotion(), MBCNodal.F(), MBCNodal.M() and
>>> MBCNodal.PutForces(), and what is the exact time step at each point in
>>> the sequence for which forces are being applied, or motion received?
>>> I have tried to look carefully at the documentation, and at the
>>> comments in libmbc, but I just can't figure it out. I've experimented
>>> with various sequences, but I would really rather be confident in what
>>> I am doing.
>>> Finally, in general, what should data_and_next be set to? What does it
>>> mean exactly? Should this change during the simulation process?
>> You should check the code in utils/test_strext_socket* for a complete
>> usage example; Makefile.am tells you what code is relevant for the
>> purely C++ version of the example tool, test_strext_socket_cxx.
>> The "data_and_next" flags sends to MBDyn both a packet with load data
>> and instructs it that for what concerns the external solver it can
>> advance one step ("ES_REGULAR_DATA_AND_GOTO_NEXT_STEP").  If the flag is
>> false, two separate messages are needed, one with loads
>> ("ES_REGULAR_DATA") and one with "advance" information
>> Hope this helps.
>> Sincerely, p.
> Thanks, but yes, I have looked quite carefully at this code, and I 
> still have some problems understanding exactly what should happen and 
> in what order. I think I need to be more specific in my question. For 
> loose coupling, is the following sequence and descriptions of what 
> happens correct?
> 1. start mbdyn process
> 2. in my process using libmbc set data_and_next true using 
> SetDataAndNext which is  equivalent to setting flag 
Not strictly needed, as data_and_next is set by default (you can check 
it by calling bDataAndNext() on the newly created object).
> 3. call GetMotion, like
> status = GetMotion ()
> which gets the initial positions velocities and accelerations at time 
> t=0. The status returns 0 if everything is ok, and there are still 
> more time steps to be calculated i.e. the current mbdyn internal 
> simulation time < end time
> 4. get the actual motion data using X, XP, XPP, Theta (or Euler123 or 
> R), Omega, OmegaP.
> Whether we can use Theta, Euler123 or R depends on what the value of 
> the Rot flag was set to,
> and using the wrong function will cause mbdyn to terminate?
No.  Communication with MBDyn is not involved so far.  If your process 
dies and the connection is closed, a signal is triggered. Unless MBDyn 
is instructed to intercept (and ignore) it (using the "no signal" 
keyword in the definition of the external force element), the signal 
causes the termination of the process.  If you call the wrong function, 
you either get garbage or cause a SIGSEGV in your own process, not in MBDyn.
> 5. calculate my initial forces and moments and get them ready to be 
> sent to mbdyn using the F() and M() methods
> 7. send the new forces to mbdyn by calling PutForces (), this is one 
> point where it is not clear what the correct sequence is. It seems 
> like I have to first call PutForces (false), then call GetMotion 
> again, but which returns the predicted motion based on these forces.
When you call PutForces you pass it a boolean that tells MBDyn whether 
you're at convergence (TRUE) or not (FALSE), and thus tell it whether it 
needs to wait for further loads or keep iterating to its own convergence 
using the last set of forces that it received.

When the flag is TRUE,
- if data_and_next == TRUE, then MBDyn expects the packet to also 
contain forces
- if data_and_next == FALSE, then MBDyn does not expect any forces 
attached to it

When the flag is FALSE, MBDyn expects the packet to contain forces

So two schemes are valid:

// data_and_next = FALSE
while (TRUE) {
     // use it to compute forces
     F(1) = 1.;
     F(2) = 2.;
     F(3) = 3.;
     if (at_convergence) {
         // don't need to set forces to any value; only the flag is sent

// data_and_next = TRUE
while (TRUE) {
     // use it to compute forces
     F(1) = 1.;
     F(2) = 2.;
     F(3) = 3.;
     // sends forces; if at_convergence == TRUE, it will be the last 
call for this time step

> 8. Apply the forces again using F() and M()
> 9. Call PutForces(true) to say the external solver has converged, and 
> mbdyn can advance
> 10. call GetMotion again to get the next motion from mbdyn. Again it's 
> not clear here what this is at this point. Is this the actual motion 
> calculated in the previous time step?
Within a time step, the first time one calls GetMotion() the *predicted* 
motion is returned.  On subsequent calls, the *corrected* motion is 
returned, i.e. the motion resulting from correcting the prediction with 
the solution increments obtained by iterating MBDyn
> 11. set forces using F() and M()
> 12. call PutForces (false) to send the forces to mbdyn
> 13. GetMotion(), this retunrs slighly differenet motion, is this the 
> predicted motion from the forces just applied?
> 15. Set forces again using F() and M()
> 14. call PutForces (true) to send forces to mbdyn
> 15. repeat from step 10, until GetMotion returns something other than 
> 0. This tells us that every time step has been calculated or some 
> other error occurred (is it possible to know which? Are there other 
> return codes?). Does this mean the motion from the very last time 
> point was obtained in the previous GetMotion call, or that the very 
> last motion cannot be obtained?
> However, I also read the following in mbc.h:
>  * if last is true and mbc_t::data_and_next is false, the output 
> buffer is not sent;
Correct, see above.  Note that in this context, "last" stands for "last 
iteration of the present time step.  For "loose coupling" you just 
exchange one motion and one set of loads, so:
- if data_and_next is TRUE, you always call PutForces() with a TRUE flag
- if data_and_next is FALSE, you call PutForces() twice, the first time 
with FALSE and the second with TRUE
>  * thus, there is no need to set forces and moments;
>  * otherwise, if mbc_t::data_and_next is true, the output buffer must 
> be filled as described above.
> Which thinks makes me think maybe I should be setting data_and_next to 
> false, and not setting the loads using F() and M()  before calling 
> PutForces(true), but if I try this mbdyn hangs, but maybe I'm supposed 
> to be changing the dataand_next setting before doing the second call 
> and back afterwards? In the python interface it seems like this is 
> something set right at the start of a simulation 
> (initialisatio/negotiation stage) and not supposed to be changed 
> during it, is this right?
Not sure I understand what you're describing above.  I have to tell you 
that we didn't experiment too much with data_and_next set to FALSE, as 
that feature was specifically requested by a certain interface that is 
no longer in use.

I hope it's clearer now.

Sincerely, p.
> Best regards,
> Richard

Pierangelo Masarati
Dipartimento di Scienze e Tecnologie Aerospaziali
Politecnico di Milano

More information about the MBDyn-users mailing list