1 /*
2  * MBDyn (C) is a multibody analysis code.
3  * http://www.mbdyn.org
4  *
5  * Copyright (C) 1996-2017
6  *
7  * Pierangelo Masarati	<masarati@aero.polimi.it>
8  * Paolo Mantegazza	<mantegazza@aero.polimi.it>
9  *
10  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
11  * via La Masa, 34 - 20156 Milano, Italy
12  * http://www.aero.polimi.it
13  *
14  * Changing this copyright notice is forbidden.
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation (version 2 of the License).
19  *
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30 
31 /*
32  * NOTE: this is intentionally configuration-independent.
33  */
34 
35 #ifndef MBC_H
36 #define MBC_H
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif /* __cplusplus */
41 
42 #include <stdint.h>
43 
44 /** \brief Legal commands
45  *
46  * The values of this enumeration appear as tags at the beginning
47  * of each communication.
48  */
49 enum ESCmd {
50 	ES_UNKNOWN				= -1,
51 	/* 1 intentionally unused */
52 	ES_REGULAR_DATA				= 2,
53 	/* 3 intentionally unused */
54 	ES_GOTO_NEXT_STEP			= 4,
55 	ES_ABORT				= 5,
56 	ES_REGULAR_DATA_AND_GOTO_NEXT_STEP	= 6,
57 	ES_NEGOTIATION				= 7,
58 	ES_OK					= 8,
59 
60 	ES_LAST
61 };
62 
63 /** \brief Parameters used to control the communication type and fields. */
64 enum MBCType {
65 	MBC_MODAL				= 0x0001U,
66 	MBC_NODAL				= 0x0002U,
67 	MBC_MODAL_NODAL_MASK			= (MBC_MODAL | MBC_NODAL),
68 
69 	MBC_REF_NODE				= 0x0004U,
70 
71 	MBC_ACCELS				= 0x0008U,
72 
73 	MBC_LABELS				= 0x0010U,
74 
75 	/** Regular nodes orientation: orientation vector */
76 	MBC_ROT_THETA				= 0x0100U,
77 	/** Regular nodes orientation: orientation matrix */
78 	MBC_ROT_MAT				= 0x0200U,
79 	/** Regular nodes orientation: Euler angles (123 sequence) */
80 	MBC_ROT_EULER_123			= 0x0400U,
81 
82 	/* add more? */
83 
84 	/** Regular nodes orientation: suppress orientation
85 	 * (also suppresses angular velocities and moments) */
86 	MBC_ROT_NONE				= 0x0000U,
87 
88 	MBC_ROT_MASK				= (MBC_ROT_THETA | MBC_ROT_MAT | MBC_ROT_EULER_123),
89 
90 	/** Reference node orientation: orientation vector */
91 	MBC_REF_NODE_ROT_THETA			= (MBC_ROT_THETA << 4),
92 	/** Reference node orientation: orientation matrix */
93 	MBC_REF_NODE_ROT_MAT			= (MBC_ROT_MAT << 4),
94 	/** Reference node orientation: Euler angles (123 sequence) */
95 	MBC_REF_NODE_ROT_EULER_123		= (MBC_ROT_EULER_123 << 4),
96 
97 	MBC_REF_NODE_ROT_MASK			= (MBC_ROT_MASK << 4),
98 
99 	MBC_LAST
100 };
101 
102 /** \brief Connection data structure (partially opaque) */
103 typedef struct {
104 	/** Opaque. */
105 	int		sock;
106 
107 	/** Opaque. */
108 	unsigned	sock_flags;
109 
110 	/** Opaque. */
111 	int		recv_flags;
112 
113 	/** Opaque. */
114 	int		send_flags;
115 
116 	/** Opaque. */
117 	uint8_t		cmd;
118 
119 	/** Flag that modifies response behavior:
120 	 * - when 0, on convergence send(2) passes ES_GOTO_NEXT_STEP (convergence);
121 	 * - when 1, on convergence send(2) passes ES_REGULAR_DATA_AND_GOTO_NEXT_STEP (convergence along with last set of new data).
122 	 *
123 	 * In most cases, should be set to 1.
124 	 */
125 	char		data_and_next;
126 
127 	/** Verbose on stdout */
128 	int		verbose;
129 
130 	/** Connect(2) timeout.  When peer is not listening:
131 	 * - a value of 0 results in immediate return with error;
132 	 * - a positive value corresponds to a timeout in seconds;
133 	 * - a negative value corresponds to never timing out.
134 	 *
135 	 * During timeout, connect(2) is periodically retried.
136 	 */
137 	int		timeout;
138 } mbc_t;
139 
140 /** \brief Opaque. */
141 /* validate command
142  *
143  * command needs to be set in mbc->cmd
144  */
145 extern int
146 mbc_check_cmd(mbc_t *mbc);
147 
148 /** \brief Opaque. */
149 /* get command from peer
150  *
151  * command is stored in mbc->cmd
152  */
153 extern int
154 mbc_get_cmd(mbc_t *mbc);
155 
156 /** \brief Opaque. */
157 /* put command to peer
158  *
159  * command needs to be set in mbc->cmd
160  */
161 extern int
162 mbc_put_cmd(mbc_t *mbc);
163 
164 /** \brief Initialize communication using "inet" socket.
165  *
166  * \param [in,out] mbc a pointer to a valid mbc_t structure
167  * \param [in] host hostname
168  * \param [in] port port number
169  *
170  * Connects to peer "inet" socket using hostname and port number;
171  * host and port must be defined.  If peer is not listening,
172  * the behavior depends on mbc_t::timeout.
173  *
174  * @return 0 on success, !0 on failure.
175  */
176 extern int
177 mbc_inet_init(mbc_t *mbc, const char *host, short unsigned port);
178 
179 /** \brief Initialize communication using "unix" socket.
180  *
181  * \param [in,out] mbc a pointer to a valid mbc_t structure
182  * \param [in] path pathname
183  *
184  * Connects to peer "unix" socket using pathname;
185  * path must be defined.  If peer is not listening,
186  * the behavior depends on mbc::timeout.
187  *
188  * @return 0 on success, !0 on failure.
189  */
190 extern int
191 mbc_unix_init(mbc_t *mbc, const char *path);
192 
193 /**
194  * \brief Reference node (AKA "rigid") stuff (partially opaque).
195  *
196  * Users do not need to access members directly;
197  * macros documented in the following should be used instead.
198  *
199  * Flags:
200  * - MBC_F_REF_NODE(mbc): true when reference node is defined
201  * - MBC_F_LABELS(mbc): true when labels communication is enabled
202  * - MBC_F_ACCELS(mbc): true when accelerations communication is enabled
203  * - MBC_F_ROT(mbc): orientation mode (see MBC_ROT_* in ::MBCType)
204  * - MBC_F_ROT_THETA(mbc): true when orientation mode is orientation vector
205  * - MBC_F_ROT_MAT(mbc): true when orientation mode is orientation matrix
206  * - MBC_F_ROT_EULER_123(mbc): true when orientation mode is Euler angles (123 sequence)
207  * - MBC_F_ROT_REF_NODE(mbc): orientation mode of reference node (see MBC_ROT_* in ::MBCType; MBC_F_REF_NODE(mbc) must be true)
208  *
209  * Fields (MBC_F_REF_NODE(mbc) must be true):
210  * - MBC_R_K_LABEL(mbc): returns the (uint32_t) label of the reference node (MBC_F_LABELS(mbc) must be true)
211  * - MBC_R_X(mbc): returns a (double *) pointer to the three components of reference node position
212  * - MBC_R_THETA(mbc): returns a (double *) pointer to the three components of the reference node orientation vector
213  *   (MBC_F_ROT_THETA(mbc) must be true)
214  * - MBC_R_R(mbc): returns a (double *) pointer to the nine components of the reference node orientation matrix,
215  *   column-major (Fortran style; MBC_F_ROT_MAT(mbc) must be true)
216  * - MBC_R_EULER_123(mbc): returns a (double *) pointer to the three components of the reference node Euler angles
217  *   (123 sequence; MBC_F_ROT_EULER_123(mbc) must be true)
218  * - MBC_R_XP(mbc): returns a (double *) pointer to the three components of reference node velocity
219  * - MBC_R_OMEGA(mbc): returns a (double *) pointer to the three components of reference node angular velocity
220  * - MBC_R_XPP(mbc): returns a (double *) pointer to the three components of reference node acceleration
221  *   (MBC_F_ACCELS(mbc) must be true)
222  * - MBC_R_OMEGAP(mbc): returns a (double *) pointer to the three components of reference node angular acceleration
223  *   (MBC_F_ACCELS(mbc) must be true)
224  * - MBC_R_D_LABEL(mbc): the (uint32_t) label of the reference node (in the output buffer; MBC_F_LABELS(mbc) must be true)
225  * - MBC_R_F(mbc): returns a (double *) pointer to the three components of reference node force
226  * - MBC_R_M(mbc): returns a (double *) pointer to the three components of reference node moment
227  * - MBC_R_KINEMATICS_SIZE(mbc): returns the size of the input buffer
228  * - MBC_R_DYNAMICS_SIZE(mbc): returns the size of the output buffer
229  * - MBC_R_SIZE(mbc): returns the cumulative size of the buffers
230  * - MBC_R_KINEMATICS(mbc): returns a (void *) pointer to the input buffer
231  * - MBC_R_DYNAMICS(mbc): returns a (void *) pointer to the output buffer
232  */
233 typedef struct {
234 	uint32_t	flags;
235 #define MBC_F(mbc)			((mbc)->mbcr.flags)
236 #define MBC_F_GET(mbc, f)		(MBC_F(mbc) & (f))
237 #define MBC_F_SET(mbc, f)		(MBC_F(mbc) |= (f))
238 #define MBC_F_RESET(mbc, f)		(MBC_F(mbc) &= ~(f))
239 
240 #define MBC_F_REF_NODE(mbc)		MBC_F_GET(mbc, MBC_REF_NODE)
241 #define MBC_F_LABELS(mbc)		MBC_F_GET(mbc, MBC_LABELS)
242 #define MBC_F_ACCELS(mbc)		MBC_F_GET(mbc, MBC_ACCELS)
243 #define MBC_F_ROT(mbc)			MBC_F_GET(mbc, MBC_ROT_MASK)
244 #define MBC_F_ROT_THETA(mbc)		MBC_F_GET(mbc, MBC_ROT_THETA)
245 #define MBC_F_ROT_MAT(mbc)		MBC_F_GET(mbc, MBC_ROT_MAT)
246 #define MBC_F_ROT_EULER_123(mbc)	MBC_F_GET(mbc, MBC_ROT_EULER_123)
247 #define MBC_U_REF_NODE_ROT_2_ROT(u)	(((u) & MBC_REF_NODE_ROT_MASK) >> 4)
248 #define MBC_U_ROT_2_REF_NODE_ROT(u)	(((u) & MBC_ROT_MASK) << 4)
249 #define MBC_F_ROT_REF_NODE(mbc)		MBC_U_REF_NODE_ROT_2_ROT(MBC_F_GET((mbc), MBC_REF_NODE_ROT_MASK))
250 #define MBC_F_REF_NODE_ROT(mbc)		MBC_F_GET(mbc, MBC_REF_NODE_ROT_MASK)
251 
252 #define MBC_F_SET_REF_NODE(mbc)		MBC_F_SET(mbc, MBC_REF_NODE)
253 #define MBC_F_SET_LABELS(mbc)		MBC_F_SET(mbc, MBC_LABELS)
254 #define MBC_F_SET_ACCELS(mbc)		MBC_F_SET(mbc, MBC_ACCELS)
255 #define MBC_F_SET_ROT_THETA(mbc)	MBC_F_SET(mbc, MBC_ROT_THETA)
256 #define MBC_F_SET_ROT_MAT(mbc)		MBC_F_SET(mbc, MBC_ROT_MAT)
257 #define MBC_F_SET_ROT_EULER_123(mbc)	MBC_F_SET(mbc, MBC_ROT_EULER_123)
258 
259 	/* reference node data */
260 	union {
261 		/* NOTE: wasting an uint32_t for each uint32_t to make sure alignment is on double */
262 		char		char_r_ptr[(2 + 2) * sizeof(uint32_t) + (3 + 9 + 3 + 3 + 3 + 3 + 3 + 3) * sizeof(double)];
263 		uint32_t	uint32_t_r_ptr[(2 + 2) + (3 + 9 + 3 + 3 + 3 + 3 + 3 + 3) * sizeof(double) / sizeof(uint32_t)];
264 		double		double_r_ptr[(2 + 2) * sizeof(uint32_t) / sizeof(double) + (3 + 9 + 3 + 3 + 3 + 3 + 3 + 3) * sizeof(double)];
265 	} r_ptr;
266 
267 	uint32_t	k_size;
268 	int32_t		r_k_label;
269 	int32_t		r_k_x;
270 	int32_t		r_k_theta;
271 	int32_t		r_k_r;
272 	int32_t		r_k_euler_123;
273 	int32_t		r_k_xp;
274 	int32_t		r_k_omega;
275 	int32_t		r_k_xpp;
276 	int32_t		r_k_omegap;
277 	uint32_t	d_size;
278 	int32_t		r_d_label;
279 	int32_t		r_d_f;
280 	int32_t		r_d_m;
281 #define MBC_R_PTR(mbc, type, off)	((off) < 0 ? NULL : ((type *)&((mbc)->mbcr.r_ptr.type ## _r_ptr[(off)])))
282 #define	MBC_R_K_LABEL(mbc)		(MBC_R_PTR((mbc), uint32_t, (mbc)->mbcr.r_k_label)[0])
283 #define	MBC_R_X(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_x))
284 #define	MBC_R_THETA(mbc)		(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_theta))
285 #define	MBC_R_R(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_r))
286 #define	MBC_R_EULER_123(mbc)		(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_euler_123))
287 #define	MBC_R_XP(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_xp))
288 #define	MBC_R_OMEGA(mbc)		(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_omega))
289 #define	MBC_R_XPP(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_xpp))
290 #define	MBC_R_OMEGAP(mbc)		(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_k_omegap))
291 #define	MBC_R_D_LABEL(mbc)		(MBC_R_PTR((mbc), uint32_t, (mbc)->mbcr.r_d_label)[0])
292 #define	MBC_R_F(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_d_f))
293 #define	MBC_R_M(mbc)			(MBC_R_PTR((mbc), double, (mbc)->mbcr.r_d_m))
294 #define MBC_R_KINEMATICS_SIZE(mbc)	((mbc)->mbcr.k_size)
295 #define MBC_R_DYNAMICS_SIZE(mbc)	((mbc)->mbcr.d_size)
296 #define MBC_R_SIZE(mbc)			(MBC_R_KINEMATICS_SIZE(mbc) + MBC_R_DYNAMICS_SIZE(mbc))
297 #define MBC_R_KINEMATICS(mbc)		((void *)(mbc)->mbcr.r_ptr.char_r_ptr)
298 #define MBC_R_DYNAMICS(mbc)		((void *)(MBC_R_KINEMATICS(mbc) + MBC_R_KINEMATICS_SIZE(mbc)))
299 } mbc_rigid_t;
300 
301 /**
302  * \brief Nodal stuff (partially opaque).
303  *
304  * Users do not need to access members directly;
305  * macros documented in the following should be used instead.
306  *
307  * Fields:
308  * - MBC_N_K_LABELS(mbc): returns a (uint32_t *) pointer to input node labels (MBC_F_LABELS(mbc) must be true)
309  * - MBC_N_X(mbc): returns a (double *) pointer to positions of nodes (first node x,y,z; second node x,y,z; ...)
310  * - MBC_N_THETA(mbc): returns a (double *) pointer to orientation vectors of nodes
311  *   (first node x,y,z; second node x,y,z; ...; MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
312  * - MBC_N_R(mbc): returns a (double *) pointer to orientation vectors of nodes
313  *   (first node r11,r21,r31,r12,r22,r32,r13,r23,r33; second node r11,...,r33; ...;
314  *   MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
315  * - MBC_N_EULER_123(mbc): returns a (double *) pointer to Euler angles of nodes
316  *   (first node x,y,z; second node x,y,z; ...; MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
317  * - MBC_N_XP(mbc): returns a (double *) pointer to velocities of nodes (first node x,y,z; second node x,y,z; ...)
318  * - MBC_N_OMEGA(mbc): returns a (double *) pointer to angular velocities of nodes
319  *   (first node x,y,z; second node x,y,z; ...; MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
320  * - MBC_N_XPP(mbc): returns a (double *) pointer to accelerations of nodes
321  *   (first node x,y,z; second node x,y,z; ...; MBC_F_ACCELS(mbc) must be true)
322  * - MBC_N_OMEGAP(mbc): returns a (double *) pointer to angular accelerations of nodes
323  *   (first node x,y,z; second node x,y,z; ...; MBC_F_ACCELS(mbc) must be true and MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
324  * - MBC_N_D_LABELS(mbc): returns a (uint32_t *) pointer to output node labels (MBC_F_LABELS(mbc) must be true)
325  * - MBC_N_F(mbc): returns a (double *) pointer to forces (first node x,y,z; second node x,y,z; ...)
326  * - MBC_N_M(mbc): returns a (double *) pointer to moments (first node x,y,z; second node x,y,z; ...;
327  *   MBC_F_ROT(mbc) must not be ::MBC_ROT_NONE)
328  * - MBC_N_KINEMATICS_SIZE(mbc): returns the size of the input buffer
329  * - MBC_N_DYNAMICS_SIZE(mbc): returns the size of the output buffer
330  * - MBC_N_SIZE(mbc): returns the cumulative size of the buffers
331  * - MBC_N_KINEMATICS(mbc): returns a (void *) pointer to the input buffer
332  * - MBC_N_DYNAMICS(mbc): returns a (void *) pointer to the output buffer
333  */
334 typedef struct {
335 	mbc_t		mbc;
336 	mbc_rigid_t	mbcr;
337 
338 	/* nodal data */
339 	uint32_t	nodes;
340 	uint32_t	k_size;
341 
342 	char		*n_ptr;
343 	/* n_k_labels optional */
344 	uint32_t	*n_k_labels;
345 	double		*n_k_x;
346 	/* n_k_theta, n_k_r, n_k_euler_123 mutually exclusive */
347 	double		*n_k_theta;
348 	double		*n_k_r;
349 	double		*n_k_euler_123;
350 	double		*n_k_xp;
351 	double		*n_k_omega;
352 	/* n_k_xpp, n_k_omegap optional */
353 	double		*n_k_xpp;
354 	double		*n_k_omegap;
355 
356 	uint32_t	d_size;
357 	/* n_d_labels optional */
358 	uint32_t	*n_d_labels;
359 	double		*n_d_f;
360 	double		*n_d_m;
361 
362 #define MBC_N_K_LABELS(mbc)		((mbc)->n_k_labels)
363 #define MBC_N_X(mbc)			((mbc)->n_k_x)
364 #define MBC_N_THETA(mbc)		((mbc)->n_k_theta)
365 #define MBC_N_R(mbc)			((mbc)->n_k_r)
366 #define MBC_N_EULER_123(mbc)		((mbc)->n_k_euler_123)
367 #define MBC_N_XP(mbc)			((mbc)->n_k_xp)
368 #define MBC_N_OMEGA(mbc)		((mbc)->n_k_omega)
369 #define MBC_N_XPP(mbc)			((mbc)->n_k_xpp)
370 #define MBC_N_OMEGAP(mbc)		((mbc)->n_k_omegap)
371 #define MBC_N_D_LABELS(mbc)		((mbc)->n_d_labels)
372 #define MBC_N_F(mbc)			((mbc)->n_d_f)
373 #define MBC_N_M(mbc)			((mbc)->n_d_m)
374 #define MBC_N_KINEMATICS_SIZE(mbc)	((mbc)->k_size)
375 #define MBC_N_DYNAMICS_SIZE(mbc)	((mbc)->d_size)
376 #define MBC_N_KINEMATICS(mbc)		((void *)(mbc)->n_ptr)
377 #define MBC_N_DYNAMICS(mbc)		((void *)(MBC_N_KINEMATICS(mbc) + MBC_N_KINEMATICS_SIZE(mbc)))
378 #define MBC_N_SIZE(mbc)			(MBC_N_KINEMATICS_SIZE(mbc) + MBC_N_DYNAMICS_SIZE(mbc))
379 } mbc_nodal_t;
380 
381 /** \brief Initialize nodal data.
382  *
383  * \param [in,out] mbc pointer to a valid mbc_nodal_t structure
384  * \param [in] refnode non-zero if reference node is defined
385  * \param [in] nodes number of nodes
386  * \param [in] labels true to enable labels
387  * \param [in] rot orientation type
388  * \param [in] accels true to enable accelerations
389  *
390  * Either reference node motion must be defined (refnode != 0),
391  * or nodes must be > 0, or both.
392  *
393  * if nodes > 0, this function calls malloc(3) to alloc memory
394  * that needs to be freed by calling mbc_nodal_destroy()
395  *
396  * if labels != 0, labels are handled as well
397  *
398  * rot must be one of ::MBCType MBC_ROT_*;
399  * if it is set to ::MBC_ROT_NONE, only positions and forces are handled.
400  *
401  * if accels != 0, accelerations are handled as well.
402  *
403  * @return 0 on success, !0 on failure.
404  */
405 extern int
406 mbc_nodal_init(mbc_nodal_t *mbc, unsigned refnode, unsigned nodes,
407 	unsigned labels, unsigned rot, unsigned accels);
408 
409 /** \brief Destroy nodal data.
410  *
411  * \param [in,out] mbc pointer to a valid mbc_nodal_t structure
412  *
413  * NOTE: does NOT free mbc.
414  *
415  * @return 0 on success, !0 on failure.
416  */
417 extern int
418 mbc_nodal_destroy(mbc_nodal_t *mbc);
419 
420 /** \brief Negotiate nodal data.
421  *
422  * \param [in] mbc pointer to a valid mbc_nodal_t structure
423  *
424  * At least reference node motion must be defined
425  * (MBC_F_REF_NODE(mbc) must be true),
426  * or nodes > 0
427  *
428  * The socket must be initialized and connected.
429  *
430  * This function sends a negotiation request to the master.
431  *
432  * @return 0 on success, !0 on failure.
433  */
434 /*
435  * the protocol consists in:
436  *
437  * - negotiation request:
438  *   - the negotiation request tag (ES_NEGOTIATION, uint8_t)
439  *   - a bunch of flags (uint32_t), containing:
440  *       - the type of interface (MBC_MODAL or MBC_NODAL)
441  *       - whether a reference node is defined, MBC_REF_NODE OR-ed to previous
442  *       - more...
443  *   - the number of nodes (uint32_t)
444  *
445  * - negotiation response:
446  *   - the negotiation response tag (ES_OK or ES_ABORT, uint8_t)
447  */
448 extern int
449 mbc_nodal_negotiate_request(mbc_nodal_t *mbc);
450 
451 /** \brief Unused. */
452 /*
453  * companion of above, provided for completeness; not used
454  */
455 extern int
456 mbc_nodal_negotiate_response(mbc_nodal_t *mbc);
457 
458 /** \brief Get nodal motion from peer.
459  *
460  * \param [in,out] pointer to a valid mbc_nodal_t structure
461  *
462  * After the call to this function succeeds:
463  * - if MBC_F_REF_NODE(mbc) is true, reference node motion can be accessed using macros MBC_R_X(mbc) and similar;
464  * - if mbc_nodal_t::nodes > 0, nodal motion can be accessed using macros MBC_N_X(mbc) and similar.
465  *
466  * @return 0 on success, !0 on failure.
467  */
468 extern int
469 mbc_nodal_get_motion(mbc_nodal_t *mbc);
470 
471 /** \brief Put forces to peer.
472  *
473  * \param [in,out] pointer to a valid mbc_nodal_t structure
474  * \param [in] last true when at convergence
475  *
476 * if last is false, before calling this function:
477  * - if MBC_F_REF_NODE(mbc) is true, force and moment must be set in storage pointed to by macros MBC_R_F(mbc), MBC_R_M(mbc)
478  * - if mbc_nodal_t::nodes > 0, nodal forces must be set in storage pointed to by macros MBC_N_F(mbc), MBC_N_M(mbc)
479  *   (the latter only if MBC_F_ROT(mbc) != ::MBC_ROT_NONE).
480  *
481  * if last is true and mbc_t::data_and_next is false, the output buffer is not sent;
482  * thus, there is no need to set forces and moments;
483  * otherwise, if mbc_t::data_and_next is true, the output buffer must be filled as described above.
484  *
485  * @return 0 on success, !0 on failure.
486  */
487 extern int
488 mbc_nodal_put_forces(mbc_nodal_t *mbc, int last);
489 
490 
491 
492 /**
493  * \brief nodal stuff (partially opaque).
494  *
495  * Users do not need to access members directly;
496  * macros documented in the following should be used instead.
497  *
498  * Fields:
499  *
500  * - MBC_Q(mbc): returns a (double *) pointer to the array of generalized coordinates
501  * - MBC_QP(mbc): returns a (double *) pointer to the array of generalized coordinates derivatives
502  * - MBC_P(mbc): returns a (double *) pointer to the array of generalized forces
503  * - MBC_M_KINEMATICS_SIZE(mbc): returns the size of the input buffer
504  * - MBC_M_DYNAMICS_SIZE(mbc): returns the size of the output buffer
505  * - MBC_M_SIZE(mbc): returns the cumulative size of the buffers
506  * - MBC_M_KINEMATICS(mbc): returns a (void *) pointer to the input buffer
507  * - MBC_M_DYNAMICS(mbc): returns a (void *) pointer to the output buffer
508  */
509 typedef struct {
510 	mbc_t		mbc;
511 	mbc_rigid_t	mbcr;
512 
513 	/* modal data */
514 	uint32_t	modes;
515 	double		*m;
516 #define MBC_Q(mbc)			(&(mbc)->m[0])
517 #define MBC_QP(mbc)			(&(mbc)->m[(mbc)->modes])
518 #define MBC_P(mbc)			(&(mbc)->m[2*(mbc)->modes])
519 #define MBC_M_KINEMATICS(mbc)		MBC_Q((mbc))
520 #define MBC_M_DYNAMICS(mbc)		MBC_P((mbc))
521 #define MBC_M_KINEMATICS_SIZE(mbc)	(2*(mbc)->modes*sizeof(double))
522 #define MBC_M_DYNAMICS_SIZE(mbc)	((mbc)->modes*sizeof(double))
523 #define MBC_M_SIZE(mbc)			(3*(mbc)->modes*sizeof(double))
524 } mbc_modal_t;
525 
526 /** \brief Initialize modal data.
527  *
528  * \param [in,out] mbc pointer to a valid mbc_modal_t structure
529  * \param [in] refnode non-zero if reference node is defined
530  * \param [in] modes number of modes
531  *
532  * Either reference node motion must be defined (refnode != 0),
533  * or modes must be > 0, or both.
534  *
535  * if modes > 0, this function calls malloc(3) to alloc memory
536  * that needs to be freed by calling mbc_modal_destroy()
537  *
538  * @return 0 on success, !0 on failure.
539  */
540 extern int
541 mbc_modal_init(mbc_modal_t *mbc, int refnode, unsigned modes);
542 
543 /** \brief Destroy modal data.
544  *
545  * \param [in,out] mbc pointer to a valid mbc_modal_t structure
546  *
547  * NOTE: does NOT free mbc.
548  *
549  * @return 0 on success, !0 on failure.
550  */
551 extern int
552 mbc_modal_destroy(mbc_modal_t *mbc);
553 
554 /** \brief Negotiate modal data.
555  *
556  * \param [in] mbc pointer to a valid mbc_modal_t structure
557  *
558  * At least reference node motion must be defined
559  * (MBC_F_REF_NODE(mbc) must be true),
560  * or modes > 0
561  *
562  * The socket must be initialized and connected.
563  *
564  * This function sends a negotiation request to the master.
565  *
566  * @return 0 on success, !0 on failure.
567  */
568 /*
569  * the protocol consists in:
570  *
571  * - negotiation request:
572  *   - the negotiation request tag (ES_NEGOTIATION, uint8_t)
573  *   - a bunch of flags (uint32_t), containing:
574  *       - the type of interface (MBC_MODAL or MBC_NODAL)
575  *       - whether a reference node is defined, MBC_REF_NODE OR-ed to previous
576  *       - more...
577  *   - the number of modes (uint32_t)
578  *
579  * - negotiation response:
580  *   - the negotiation response tag (ES_OK or ES_ABORT, uint8_t)
581  */
582 extern int
583 mbc_modal_negotiate_request(mbc_modal_t *mbc);
584 
585 /** \brief Unused.
586  *
587  * companion of above, provided for completeness; not used
588  */
589 extern int
590 mbc_modal_negotiate_response(mbc_modal_t *mbc);
591 
592 /** \brief Get modal motion from peer.
593  *
594  * \param [in,out] pointer to a valid mbc_modal_t structure
595  *
596  * After the call to this function succeeds:
597  * - if MBC_F_REF_NODE(mbc) is true, reference node motion can be accessed using macros MBC_R_X(mbc) and similar;
598  * - if mbc_modal_t::modes > 0, modal motion can be accessed using macros MBC_Q(mbc) and similar.
599  *
600  * @return 0 on success, !0 on failure.
601  */
602 extern int
603 mbc_modal_get_motion(mbc_modal_t *mbc);
604 
605 /** \brief Put forces to peer.
606  *
607  * \param [in,out] mbc pointer to a valid mbc_modal_t structure
608  * \param [in] last true when at convergence
609  *
610  * if last is false, before calling this function:
611  * - if MBC_F_REF_NODE(mbc) is true, force and moment must be set in storage pointed to by macros MBC_R_F(mbc), MBC_R_M(mbc)
612  * - if mbc_modal_t::modes > 0, nodal forces must be set in storage pointed to by macro MBC_P(mbc)
613  *
614  * if last is true and mbc_t::data_and_next is false, the output buffer is not sent;
615  * thus, there is no need to set generalized forces;
616  * otherwise, if mbc_t::data_and_next is true, the output buffer must be filled as described above.
617  *
618  * @return 0 on success, !0 on failure.
619  */
620 extern int
621 mbc_modal_put_forces(mbc_modal_t *mbc, int last);
622 
623 #ifdef __cplusplus
624 }
625 #endif /* __cplusplus */
626 
627 #endif /* MBC_H */
628