1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/mbdyn/struct/strforce.cc,v 1.47 2017/07/03 22:22:09 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2017
7  *
8  * Pierangelo Masarati	<masarati@aero.polimi.it>
9  * Paolo Mantegazza	<mantegazza@aero.polimi.it>
10  *
11  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12  * via La Masa, 34 - 20156 Milano, Italy
13  * http://www.aero.polimi.it
14  *
15  * Changing this copyright notice is forbidden.
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation (version 2 of the License).
20  *
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  */
31 
32 /* Forze */
33 
34 #include "mbconfig.h"           /* This goes first in every *.c,*.cc file */
35 
36 #include <cfloat>
37 
38 #include "dataman.h"
39 #include "strforce.h"
40 #include "strforce_impl.h"
41 #include "tpldrive_impl.h"
42 
43 /* AbsoluteDispForce - begin */
44 
45 /* Costruttore non banale */
46 
AbsoluteDispForce(unsigned int uL,const StructDispNode * pN,const TplDriveCaller<Vec3> * pDC,flag fOut)47 AbsoluteDispForce::AbsoluteDispForce(unsigned int uL,
48 	const StructDispNode* pN,
49 	const TplDriveCaller<Vec3>* pDC,
50 	flag fOut)
51 : Elem(uL, fOut),
52 Force(uL, fOut),
53 f(pDC),
54 pNode(pN)
55 #ifdef USE_NETCDF
56 ,
57 Var_F(0)
58 #endif // USE_NETCDF
59 {
60 	NO_OP;
61 }
62 
63 
~AbsoluteDispForce(void)64 AbsoluteDispForce::~AbsoluteDispForce(void)
65 {
66 	NO_OP;
67 }
68 
69 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const70 AbsoluteDispForce::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
71 {
72 	*piNumRows = 3;
73 	*piNumCols = 1;
74 }
75 
76 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const77 AbsoluteDispForce::InitialWorkSpaceDim(
78 	integer* piNumRows,
79 	integer* piNumCols) const
80 {
81 	*piNumRows = 3;
82 	*piNumCols = 1;
83 }
84 
85 /* Contributo al file di restart */
86 std::ostream&
Restart(std::ostream & out) const87 AbsoluteDispForce::Restart(std::ostream& out) const
88 {
89 	Force::Restart(out) << ", absolute displacement, "
90 		<< pNode->GetLabel() << ", ",
91 		f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
92 	return out;
93 }
94 
95 /* Assembla il residuo */
96 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)97 AbsoluteDispForce::AssRes(SubVectorHandler& WorkVec,
98 	doublereal /* dCoef */ ,
99 	const VectorHandler& /* XCurr */ ,
100 	const VectorHandler& /* XPrimeCurr */ )
101 {
102 	DEBUGCOUT("Entering AbsoluteDispForce::AssRes()" << std::endl);
103 
104 	integer iNumRows;
105 	integer iNumCols;
106 	WorkSpaceDim(&iNumRows, &iNumCols);
107 	WorkVec.ResizeReset(iNumRows);
108 
109 	/* Indici delle incognite del nodo */
110 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex();
111 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
112 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
113 	}
114 
115 	WorkVec.Add(1, f.Get());
116 
117 	return WorkVec;
118 }
119 
120 /* Inverse Dynamics*/
121 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler & XCurr,const VectorHandler & XPrimeCurr,const VectorHandler &,InverseDynamics::Order iOrder)122 AbsoluteDispForce::AssRes(SubVectorHandler& WorkVec,
123 	const VectorHandler& XCurr,
124 	const VectorHandler& XPrimeCurr,
125 	const VectorHandler& /* XPrimePrimeCurr */ ,
126 	InverseDynamics::Order iOrder)
127 
128 {
129 	DEBUGCOUT("Entering AbsoluteDispForce::AssRes()" << std::endl);
130 
131 	return AssRes(WorkVec, 1., XCurr, XPrimeCurr);
132 }
133 
134 void
OutputPrepare(OutputHandler & OH)135 AbsoluteDispForce::OutputPrepare(OutputHandler& OH)
136 {
137 	if (bToBeOutput()) {
138 #ifdef USE_NETCDF
139 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
140 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
141 
142 			std::ostringstream os;
143 			os << "elem.force." << GetLabel();
144 			(void)OH.CreateVar(os.str(), "absolute displacement");
145 
146 			// joint sub-data
147 			os << '.';
148 			Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
149 				"force components (x, y, z)");
150 		}
151 #endif // USE_NETCDF
152 	}
153 }
154 
155 void
Output(OutputHandler & OH) const156 AbsoluteDispForce::Output(OutputHandler& OH) const
157 {
158 	if (bToBeOutput()) {
159 #ifdef USE_NETCDF
160 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
161 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
162 		}
163 #endif // USE_NETCDF
164 
165 		if (OH.UseText(OutputHandler::FORCES)) {
166 			OH.Forces()
167 				<< GetLabel()
168 				<< " " << pNode->GetLabel()
169 				<< " " << f.Get()
170 				<< " " << pNode->GetXCurr()
171 				<< std::endl;
172 		}
173 	}
174 }
175 
176 
177 /* Contributo al residuo durante l'assemblaggio iniziale */
178 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)179 AbsoluteDispForce::InitialAssRes(SubVectorHandler& WorkVec,
180 	const VectorHandler& /* XCurr */ )
181 {
182 	DEBUGCOUT("Entering AbsoluteDispForce::InitialAssRes()" << std::endl);
183 
184 	integer iNumRows;
185 	integer iNumCols;
186 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
187 	WorkVec.ResizeReset(iNumRows);
188 
189 	/* Indici delle incognite del nodo */
190 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex();
191 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
192 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
193 	}
194 
195 	WorkVec.Add(1, f.Get());
196 
197 	return WorkVec;
198 }
199 
200 void
GetConnectedNodes(std::vector<const Node * > & connectedNodes) const201 AbsoluteDispForce::GetConnectedNodes(std::vector<const Node *>& connectedNodes) const
202 {
203 	connectedNodes.resize(1);
204 	connectedNodes[0] = pNode;
205 }
206 
207 /* AbsoluteDispForce - end */
208 
209 
210 /* AbsoluteInternalDispForce - begin */
211 
212 /* Costruttore non banale */
213 
AbsoluteInternalDispForce(unsigned int uL,const StructDispNode * pN1,const StructDispNode * pN2,const TplDriveCaller<Vec3> * pDC,flag fOut)214 AbsoluteInternalDispForce::AbsoluteInternalDispForce(unsigned int uL,
215 	const StructDispNode* pN1,
216 	const StructDispNode* pN2,
217 	const TplDriveCaller<Vec3>* pDC,
218 	flag fOut)
219 : Elem(uL, fOut),
220 Force(uL, fOut),
221 f(pDC),
222 pNode1(pN1),
223 pNode2(pN2)
224 #ifdef USE_NETCDF
225 ,
226 Var_F(0)
227 #endif // USE_NETCDF
228 {
229 	NO_OP;
230 }
231 
232 
~AbsoluteInternalDispForce(void)233 AbsoluteInternalDispForce::~AbsoluteInternalDispForce(void)
234 
235 {
236 	NO_OP;
237 }
238 
239 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const240 AbsoluteInternalDispForce::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
241 {
242 	*piNumRows = 6;
243 	*piNumCols = 1;
244 }
245 
246 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const247 AbsoluteInternalDispForce::InitialWorkSpaceDim(
248 	integer* piNumRows,
249 	integer* piNumCols) const
250 {
251 	*piNumRows = 6;
252 	*piNumCols = 1;
253 }
254 
255 /* Contributo al file di restart */
256 std::ostream&
Restart(std::ostream & out) const257 AbsoluteInternalDispForce::Restart(std::ostream& out) const
258 {
259 	Force::Restart(out) << ", absolute internal displacement, "
260 		<< pNode1->GetLabel() << ", "
261 		<< pNode2->GetLabel() << ", ",
262 		f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
263 	return out;
264 }
265 
266 /* Assembla il residuo */
267 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)268 AbsoluteInternalDispForce::AssRes(SubVectorHandler& WorkVec,
269 	doublereal /* dCoef */ ,
270 	const VectorHandler& /* XCurr */ ,
271 	const VectorHandler& /* XPrimeCurr */ )
272 {
273 	DEBUGCOUT("Entering AbsoluteDispForce::AssRes()" << std::endl);
274 
275 	integer iNumRows;
276 	integer iNumCols;
277 	WorkSpaceDim(&iNumRows, &iNumCols);
278 	WorkVec.ResizeReset(iNumRows);
279 
280 	/* Indici delle incognite del nodo */
281 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex();
282 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex();
283 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
284 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
285 		WorkVec.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
286 	}
287 
288 	Vec3 fTmp(f.Get());
289 	WorkVec.Add(1, fTmp);
290 	WorkVec.Sub(3 + 1, fTmp);
291 
292 	return WorkVec;
293 }
294 
295 /* Inverse Dynamics*/
296 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler & XCurr,const VectorHandler & XPrimeCurr,const VectorHandler &,InverseDynamics::Order iOrder)297 AbsoluteInternalDispForce::AssRes(SubVectorHandler& WorkVec,
298 	const VectorHandler& XCurr,
299 	const VectorHandler& XPrimeCurr,
300 	const VectorHandler& /* XPrimePrimeCurr */ ,
301 	InverseDynamics::Order iOrder)
302 {
303 	DEBUGCOUT("Entering AbsoluteDispForce::AssRes()" << std::endl);
304 
305 	return AssRes(WorkVec, 1., XCurr, XPrimeCurr);
306 }
307 
308 void
OutputPrepare(OutputHandler & OH)309 AbsoluteInternalDispForce::OutputPrepare(OutputHandler& OH)
310 {
311 	if (bToBeOutput()) {
312 #ifdef USE_NETCDF
313 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
314 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
315 
316 			std::ostringstream os;
317 			os << "elem.force." << GetLabel();
318 			(void)OH.CreateVar(os.str(), "internal absolute displacement");
319 
320 			// joint sub-data
321 			os << '.';
322 			Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
323 				"force components (x, y, z)");
324 		}
325 #endif // USE_NETCDF
326 	}
327 }
328 
329 void
Output(OutputHandler & OH) const330 AbsoluteInternalDispForce::Output(OutputHandler& OH) const
331 {
332 	if (bToBeOutput()) {
333 #ifdef USE_NETCDF
334 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
335 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
336 		}
337 #endif // USE_NETCDF
338 
339 		if (OH.UseText(OutputHandler::FORCES)) {
340 			Vec3 fTmp(f.Get());
341 			OH.Forces()
342 				<< GetLabel()
343 				<< " " << pNode1->GetLabel()
344 				<< " " << fTmp
345 				<< " " << pNode1->GetXCurr()
346 				<< " " << pNode2->GetLabel()
347 				<< " " << -fTmp
348 				<< " " << pNode2->GetXCurr()
349 				<< std::endl;
350 		}
351 
352 		/* TODO: NetCDF */
353 	}
354 }
355 
356 
357 /* Contributo al residuo durante l'assemblaggio iniziale */
358 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)359 AbsoluteInternalDispForce::InitialAssRes(SubVectorHandler& WorkVec,
360 	const VectorHandler& /* XCurr */ )
361 {
362 	DEBUGCOUT("Entering AbsoluteDispForce::InitialAssRes()" << std::endl);
363 
364 	integer iNumRows;
365 	integer iNumCols;
366 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
367 	WorkVec.ResizeReset(iNumRows);
368 
369 	/* Indici delle incognite del nodo */
370 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex();
371 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex();
372 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
373 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
374 		WorkVec.PutRowIndex(3 + iCnt, iFirstPositionIndex2 + iCnt);
375 	}
376 
377 	Vec3 fTmp(f.Get());
378 	WorkVec.Add(1, fTmp);
379 	WorkVec.Sub(3 + 1, fTmp);
380 
381 	return WorkVec;
382 }
383 
384 void
GetConnectedNodes(std::vector<const Node * > & connectedNodes) const385 AbsoluteInternalDispForce::GetConnectedNodes(std::vector<const Node *>& connectedNodes) const
386 {
387 	connectedNodes.resize(2);
388 	connectedNodes[0] = pNode1;
389 	connectedNodes[1] = pNode2;
390 }
391 
392 /* AbsoluteDispForce - end */
393 
394 
395 /* StructuralForce - begin */
396 
397 /* Costruttore */
StructuralForce(unsigned int uL,const StructNode * pN,const TplDriveCaller<Vec3> * pDC,flag fOut)398 StructuralForce::StructuralForce(unsigned int uL,
399 	const StructNode* pN,
400 	const TplDriveCaller<Vec3>* pDC,
401 	flag fOut)
402 : Elem(uL, fOut),
403 Force(uL, fOut),
404 f(pDC),
405 pNode(pN)
406 #ifdef USE_NETCDF
407 ,
408 Var_F(0)
409 #endif // USE_NETCDF
410 {
411 	ASSERT(pNode != NULL);
412 	ASSERT(pNode->GetNodeType() == Node::STRUCTURAL);
413 	ASSERT(pDC != NULL);
414 }
415 
416 
~StructuralForce(void)417 StructuralForce::~StructuralForce(void)
418 {
419 	NO_OP;
420 }
421 
422 void
GetConnectedNodes(std::vector<const Node * > & connectedNodes) const423 StructuralForce::GetConnectedNodes(std::vector<const Node *>& connectedNodes) const {
424 	connectedNodes.resize(1);
425 	connectedNodes[0] = pNode;
426 }
427 
428 /* StructuralForce - end */
429 
430 
431 /* AbsoluteForce - begin */
432 
433 /* Costruttore non banale */
434 
AbsoluteForce(unsigned int uL,const StructNode * pN,const TplDriveCaller<Vec3> * pDC,const Vec3 & TmpArm,flag fOut)435 AbsoluteForce::AbsoluteForce(unsigned int uL,
436 	const StructNode* pN,
437 	const TplDriveCaller<Vec3>* pDC,
438 	const Vec3& TmpArm,
439 	flag fOut)
440 : Elem(uL, fOut),
441 StructuralForce(uL, pN, pDC, fOut),
442 Arm(TmpArm)
443 #ifdef USE_NETCDF
444 ,
445 Var_A(0)
446 #endif // USE_NETCDF
447 {
448 	NO_OP;
449 }
450 
451 
~AbsoluteForce(void)452 AbsoluteForce::~AbsoluteForce(void)
453 {
454 	NO_OP;
455 }
456 
457 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const458 AbsoluteForce::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
459 {
460 	*piNumRows = 6;
461 	*piNumCols = 3;
462 }
463 
464 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const465 AbsoluteForce::InitialWorkSpaceDim(
466 	integer* piNumRows,
467 	integer* piNumCols) const
468 {
469 	*piNumRows = 12;
470 	*piNumCols = 6;
471 }
472 
473 /* Contributo al file di restart */
474 std::ostream&
Restart(std::ostream & out) const475 AbsoluteForce::Restart(std::ostream& out) const
476 {
477 	Force::Restart(out) << ", absolute, "
478 		<< pNode->GetLabel() << ", position, reference, node, ",
479 		Arm.Write(out, ", ") << ", ";
480 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
481 }
482 
483 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)484 AbsoluteForce::AssJac(VariableSubMatrixHandler& WorkMat,
485 	doublereal dCoef,
486 	const VectorHandler& /* XCurr */ ,
487 	const VectorHandler& /* XPrimeCurr */ )
488 {
489 	DEBUGCOUT("Entering AbsoluteForce::AssJac()" << std::endl);
490 
491 	FullSubMatrixHandler& WM = WorkMat.SetFull();
492 
493 	/* Dimensiona e resetta la matrice di lavoro */
494 	WM.ResizeReset(3, 3);
495 
496 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex() + 3;
497 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex() + 3;
498 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
499 		WM.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
500 		WM.PutColIndex(iCnt, iFirstPositionIndex + iCnt);
501 	}
502 
503 	/* Dati */
504 	Vec3 TmpArm(pNode->GetRRef()*Arm);
505 
506 	/* |    F/\   |           |   F  |
507 	 * |          | Delta_g = |      |
508 	 * | (d/\F)/\ |           | d/\F |
509 	 */
510 
511 	WM.Sub(1, 1, Mat3x3(MatCrossCross, f.Get(), TmpArm*dCoef));
512 
513 	return WorkMat;
514 }
515 
516 
517 /* Assembla il residuo */
518 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)519 AbsoluteForce::AssRes(SubVectorHandler& WorkVec,
520 	doublereal /* dCoef */ ,
521 	const VectorHandler& /* XCurr */ ,
522 	const VectorHandler& /* XPrimeCurr */ )
523 {
524 	DEBUGCOUT("Entering AbsoluteForce::AssRes()" << std::endl);
525 
526 	integer iNumRows;
527 	integer iNumCols;
528 	WorkSpaceDim(&iNumRows, &iNumCols);
529 	WorkVec.ResizeReset(iNumRows);
530 
531 	/* Indici delle incognite del nodo */
532 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex();
533 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
534 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
535 	}
536 
537 	const Mat3x3& R(pNode->GetRCurr());
538 	Vec3 F(f.Get());
539 	Vec3 M((R*Arm).Cross(F));
540 
541 	WorkVec.Add(1, F);
542 	WorkVec.Add(4, M);
543 
544 	return WorkVec;
545 }
546 
547 /* Inverse Dynamics*/
548 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)549 AbsoluteForce::AssRes(SubVectorHandler& WorkVec,
550 	const VectorHandler& /* XCurr */ ,
551 	const VectorHandler& /* XPrimeCurr */ ,
552 	const VectorHandler& /* XPrimePrimeCurr */ ,
553 	InverseDynamics::Order iOrder)
554 {
555 	DEBUGCOUT("Entering AbsoluteForce::AssRes()" << std::endl);
556 
557 	integer iNumRows;
558 	integer iNumCols;
559 	WorkSpaceDim(&iNumRows, &iNumCols);
560 	WorkVec.ResizeReset(iNumRows);
561 
562 	/* Indici delle incognite del nodo */
563 	integer iFirstMomentumIndex = pNode->iGetFirstPositionIndex();
564 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
565 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
566 	}
567 
568 	const Mat3x3& R(pNode->GetRCurr());
569 	Vec3 F(f.Get());
570 	Vec3 M((R*Arm).Cross(F));
571 
572 	WorkVec.Add(1, F);
573 	WorkVec.Add(4, M);
574 
575 	return WorkVec;
576 }
577 
578 void
OutputPrepare(OutputHandler & OH)579 AbsoluteForce::OutputPrepare(OutputHandler& OH)
580 {
581 	if (bToBeOutput()) {
582 #ifdef USE_NETCDF
583 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
584 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
585 
586 			std::ostringstream os;
587 			os << "elem.force." << GetLabel();
588 			(void)OH.CreateVar(os.str(), "absolute");
589 
590 			// joint sub-data
591 			os << '.';
592 			Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
593 				"global force components (x, y, z)");
594 
595 			Var_A = OH.CreateVar<Vec3>(os.str() + "Arm", "m",
596 				"arm in global frame (x, y, z)");
597 		}
598 #endif // USE_NETCDF
599 	}
600 }
601 
602 void
Output(OutputHandler & OH) const603 AbsoluteForce::Output(OutputHandler& OH) const
604 {
605 	if (bToBeOutput()) {
606 #ifdef USE_NETCDF
607 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
608 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
609 			Var_A->put_rec((pNode->GetXCurr() + pNode->GetRCurr()*Arm).pGetVec(), OH.GetCurrentStep());
610 		}
611 #endif // USE_NETCDF
612 
613 		if (OH.UseText(OutputHandler::FORCES)) {
614 			OH.Forces()
615 				<< GetLabel()
616 				<< " " << pNode->GetLabel()
617 				<< " " << f.Get()
618 				<< " " << pNode->GetXCurr() + pNode->GetRCurr()*Arm
619 				<< std::endl;
620 		}
621 
622 		/* TODO: NetCDF */
623 	}
624 }
625 
626 
627 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
628 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)629 AbsoluteForce::InitialAssJac(VariableSubMatrixHandler& WorkMat,
630 	const VectorHandler& /* XCurr */ )
631 {
632 	DEBUGCOUT("Entering AbsoluteForce::InitialAssJac()" << std::endl);
633 
634 	FullSubMatrixHandler& WM = WorkMat.SetFull();
635 
636 	/* Dimensiona e resetta la matrice di lavoro */
637 	WM.ResizeReset(6, 6);
638 
639 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex() + 3;
640 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
641 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
642 		WM.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
643 		WM.PutRowIndex(3+iCnt, iFirstVelocityIndex + iCnt);
644 		WM.PutColIndex(iCnt, iFirstPositionIndex + iCnt);
645 		WM.PutColIndex(3+iCnt, iFirstVelocityIndex + iCnt);
646 	}
647 
648 	/* Dati */
649 	Vec3 TmpArm(pNode->GetRRef()*Arm);
650 	Vec3 TmpDir = f.Get();
651 	const Vec3& Omega(pNode->GetWRef());
652 
653 	/* |    F/\   |           |   F  |
654 	 * |          | Delta_g = |      |
655 	 * | (d/\F)/\ |           | d/\F |
656 	 */
657 
658 	Mat3x3 MTmp(MatCrossCross, TmpDir, TmpArm);
659 
660 	WM.Sub(1, 1, MTmp);
661 	WM.Sub(4, 1, Mat3x3(MatCrossCross, TmpDir, Omega)*Mat3x3(MatCross, TmpArm));
662 	WM.Sub(4, 4, MTmp);
663 
664 	return WorkMat;
665 }
666 
667 
668 /* Contributo al residuo durante l'assemblaggio iniziale */
669 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)670 AbsoluteForce::InitialAssRes(SubVectorHandler& WorkVec,
671 	const VectorHandler& /* XCurr */ )
672 {
673 	DEBUGCOUT("Entering AbsoluteForce::InitialAssRes()" << std::endl);
674 
675 	integer iNumRows;
676 	integer iNumCols;
677 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
678 	WorkVec.ResizeReset(iNumRows);
679 
680 	/* Indici delle incognite del nodo */
681 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex();
682 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
683 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
684 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
685 		WorkVec.PutRowIndex(6+iCnt, iFirstVelocityIndex + iCnt);
686 	}
687 
688 	/* Dati */
689 	const Mat3x3& R(pNode->GetRCurr());
690 	Vec3 TmpDir(f.Get());
691 	Vec3 TmpArm(R*Arm);
692 	const Vec3& Omega(pNode->GetWCurr());
693 
694 	WorkVec.Add(1, TmpDir);
695 	WorkVec.Add(4, TmpArm.Cross(TmpDir));
696 	/* In 7 non c'e' nulla */
697 	WorkVec.Add(10, (Omega.Cross(TmpArm)).Cross(TmpDir));
698 
699 	return WorkVec;
700 }
701 
702 /* AbsoluteForce - end */
703 
704 
705 /* FollowerForce - begin */
706 
707 /* Costruttore non banale */
708 
FollowerForce(unsigned int uL,const StructNode * pN,const TplDriveCaller<Vec3> * pDC,const Vec3 & TmpArm,flag fOut)709 FollowerForce::FollowerForce(unsigned int uL, const StructNode* pN,
710 	const TplDriveCaller<Vec3>* pDC,
711 	const Vec3& TmpArm,
712 	flag fOut)
713 : Elem(uL, fOut),
714 StructuralForce(uL, pN, pDC, fOut),
715 Arm(TmpArm)
716 #ifdef USE_NETCDF
717 ,
718 Var_A(0)
719 #endif // USE_NETCDF
720 {
721 	NO_OP;
722 }
723 
724 
~FollowerForce(void)725 FollowerForce::~FollowerForce(void)
726 {
727 	NO_OP;
728 }
729 
730 
731 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const732 FollowerForce::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
733 {
734 	*piNumRows = 6;
735 	*piNumCols = 3;
736 }
737 
738 
739 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const740 FollowerForce::InitialWorkSpaceDim(
741 	integer* piNumRows,
742 	integer* piNumCols) const
743 {
744 	*piNumRows = 12;
745 	*piNumCols = 6;
746 }
747 
748 
749 /* Contributo al file di restart */
750 std::ostream&
Restart(std::ostream & out) const751 FollowerForce::Restart(std::ostream& out) const
752 {
753 	Force::Restart(out) << ", follower, "
754 		<< pNode->GetLabel()
755 		<< ", position, reference, node, ",
756 		Arm.Write(out, ", ") << ", ";
757 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
758 }
759 
760 
761 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)762 FollowerForce::AssJac(VariableSubMatrixHandler& WorkMat,
763 	doublereal dCoef,
764 	const VectorHandler& /* XCurr */ ,
765 	const VectorHandler& /* XPrimeCurr */ )
766 {
767 	DEBUGCOUT("Entering FollowerForce::AssJac()" << std::endl);
768 
769 	FullSubMatrixHandler& WM = WorkMat.SetFull();
770 
771 	/* Dimensiona e resetta la matrice di lavoro */
772 	integer iNumRows = 0;
773 	integer iNumCols = 0;
774 	WorkSpaceDim(&iNumRows, &iNumCols);
775 	WM.ResizeReset(iNumRows, iNumCols);
776 
777 	integer iFirstRotationIndex = pNode->iGetFirstPositionIndex() + 3;
778 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex();
779 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
780 		WM.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);     /* forza */
781 		WM.PutRowIndex(3 + iCnt, iFirstMomentumIndex + 3 + iCnt); /* coppia */
782 		WM.PutColIndex(iCnt, iFirstRotationIndex + iCnt);     /* rotazione */
783 	}
784 
785 	/* Dati */
786 	const Mat3x3& R(pNode->GetRRef());
787 	Vec3 TmpDir(R*(f.Get()*dCoef));
788 	Vec3 TmpArm(R*Arm);
789 
790 	/* |    F/\   |           |   F  |
791 	 * |          | Delta_g = |      |
792 	 * | (d/\F)/\ |           | d/\F |
793 	 */
794 
795 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
796 	WM.Add(4, 1, Mat3x3(MatCross, TmpArm.Cross(TmpDir)));
797 
798 	return WorkMat;
799 }
800 
801 
802 /* Assembla il residuo */
803 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)804 FollowerForce::AssRes(SubVectorHandler& WorkVec,
805 	doublereal /* dCoef */ ,
806 	const VectorHandler& /* XCurr */ ,
807 	const VectorHandler& /* XPrimeCurr */ )
808 {
809 	DEBUGCOUT("Entering FollowerForce::AssRes()" << std::endl);
810 
811 	integer iNumRows;
812 	integer iNumCols;
813 	WorkSpaceDim(&iNumRows, &iNumCols);
814 	WorkVec.ResizeReset(iNumRows);
815 
816 	/* Indici delle incognite del nodo */
817 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex();
818 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
819 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
820 	}
821 
822 	/* Dati */
823 	const Mat3x3& R(pNode->GetRCurr());
824 	Vec3 TmpDir = f.Get();
825 	Vec3 F(R*TmpDir);
826 	Vec3 M(R*Arm.Cross(TmpDir));
827 
828 	WorkVec.Add(1, F);
829 	WorkVec.Add(4, M);
830 
831 	return WorkVec;
832 }
833 
834 
835 /* Inverse Dynamics*/
836 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)837 FollowerForce::AssRes(SubVectorHandler& WorkVec,
838 	const VectorHandler& /* XCurr */ ,
839 	const VectorHandler& /* XPrimeCurr */ ,
840 	const VectorHandler& /* XPrimePrimeCurr */ ,
841 	InverseDynamics::Order iOrder)
842 {
843 	DEBUGCOUT("Entering FollowerForce::AssRes()" << std::endl);
844 
845 	integer iNumRows;
846 	integer iNumCols;
847 	WorkSpaceDim(&iNumRows, &iNumCols);
848 	WorkVec.ResizeReset(iNumRows);
849 
850 	/* Indici delle incognite del nodo */
851 	integer iFirstMomentumIndex = pNode->iGetFirstPositionIndex();
852 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
853 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex+iCnt);
854 	}
855 
856 	/* Dati */
857 	const Mat3x3& R(pNode->GetRCurr());
858 	Vec3 TmpDir = f.Get();
859 	Vec3 F(R*TmpDir);
860 	Vec3 M(R*Arm.Cross(TmpDir));
861 
862 	WorkVec.Add(1, F);
863 	WorkVec.Add(4, M);
864 
865 	return WorkVec;
866 }
867 
868 void
OutputPrepare(OutputHandler & OH)869 FollowerForce::OutputPrepare(OutputHandler& OH)
870 {
871 	if (bToBeOutput()) {
872 #ifdef USE_NETCDF
873 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
874 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
875 
876 			std::ostringstream os;
877 			os << "elem.force." << GetLabel();
878 			(void)OH.CreateVar(os.str(), "follower");
879 
880 			// joint sub-data
881 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
882 				os << '.';
883 				Var_F = OH.CreateVar<Vec3>(os.str() + "f", "N",
884 					"local force components (x, y, z)");
885 
886 			} else {
887 				os << '.';
888 				Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
889 					"global force components (x, y, z)");
890 			}
891 
892 			Var_A = OH.CreateVar<Vec3>(os.str() + "Arm", "m",
893 				"arm in global frame (x, y, z)");
894 		}
895 #endif // USE_NETCDF
896 	}
897 }
898 
899 void
Output(OutputHandler & OH) const900 FollowerForce::Output(OutputHandler& OH) const
901 {
902 	if (bToBeOutput()) {
903 #ifdef USE_NETCDF
904 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
905 			if (fToBeOutput() & OUTPUT_REL) {
906 				Var_F->put_rec((f.Get()).pGetVec(), OH.GetCurrentStep());
907 			} else {
908 				Var_F->put_rec((pNode->GetRCurr()*f.Get()).pGetVec(), OH.GetCurrentStep());
909 			}
910 			Var_A->put_rec((pNode->GetXCurr() + pNode->GetRCurr()*Arm).pGetVec(), OH.GetCurrentStep());
911 		}
912 #endif // USE_NETCDF
913 
914 		if (OH.UseText(OutputHandler::FORCES)) {
915 			OH.Forces()
916 				<< GetLabel()
917 				<< " " << pNode->GetLabel();
918 
919 			if (fToBeOutput() & OUTPUT_REL) {
920 				OH.Forces()
921 					<< " " << f.Get();
922 
923 			} else {
924 				OH.Forces()
925 					<< " " << pNode->GetRCurr()*f.Get();
926 			}
927 
928 			OH.Forces()
929 				<< " " << pNode->GetXCurr() + pNode->GetRCurr()*Arm
930 				<< std::endl;
931 		}
932 	}
933 }
934 
935 
936 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
937 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)938 FollowerForce::InitialAssJac(VariableSubMatrixHandler& WorkMat,
939 	const VectorHandler& /* XCurr */ )
940 {
941 	DEBUGCOUT("Entering FollowerForce::InitialAssJac()" << std::endl);
942 
943 	FullSubMatrixHandler& WM = WorkMat.SetFull();
944 
945 	/* Dimensiona e resetta la matrice di lavoro */
946 	WM.ResizeReset(12, 6);
947 
948 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex();
949 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
950 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
951 		WM.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
952 		WM.PutRowIndex(3 + iCnt, iFirstPositionIndex + 3 + iCnt);
953 		WM.PutRowIndex(6 + iCnt, iFirstVelocityIndex + iCnt);
954 		WM.PutRowIndex(9 + iCnt, iFirstVelocityIndex + 3 + iCnt);
955 		WM.PutColIndex(iCnt, iFirstPositionIndex + 3 + iCnt);
956 		WM.PutColIndex(3 + iCnt, iFirstVelocityIndex + 3 + iCnt);
957 	}
958 
959 	/* Dati */
960 	const Mat3x3& R(pNode->GetRRef());
961 	Vec3 TmpArm(R*Arm);
962 	Vec3 TmpDir = R*f.Get();
963 	const Vec3& Omega(pNode->GetWRef());
964 
965 	/* |    F/\   |           |   F  |
966 	 * |          | Delta_g = |      |
967 	 * | (d/\F)/\ |           | d/\F |
968 	 */
969 
970 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
971 	WM.Add(4, 1, Mat3x3(MatCross, TmpArm.Cross(TmpDir)));
972 	WM.Add(7, 1, Mat3x3(MatCrossCross, Omega, TmpDir));
973 	WM.Add(7, 4, Mat3x3(MatCross, TmpDir));
974 	WM.Add(10, 1, Mat3x3(MatCrossCross, Omega, TmpArm.Cross(TmpDir)));
975 	WM.Add(10, 4, Mat3x3(MatCross, TmpArm.Cross(TmpDir)));
976 
977 	return WorkMat;
978 }
979 
980 
981 /* Contributo al residuo durante l'assemblaggio iniziale */
982 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)983 FollowerForce::InitialAssRes(SubVectorHandler& WorkVec,
984 	const VectorHandler& /* XCurr */ )
985 {
986 	DEBUGCOUT("Entering FollowerForce::InitialAssRes()" << std::endl);
987 
988 	integer iNumRows;
989 	integer iNumCols;
990 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
991 	WorkVec.ResizeReset(iNumRows);
992 
993 	/* Indici delle incognite del nodo */
994 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex();
995 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
996 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
997 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
998 		WorkVec.PutRowIndex(6 + iCnt, iFirstVelocityIndex + iCnt);
999 	}
1000 
1001 	/* Dati */
1002 	const Mat3x3& R(pNode->GetRCurr());
1003 	Vec3 TmpDir(R*f.Get());
1004 	Vec3 TmpArm(R*Arm);
1005 	const Vec3& Omega(pNode->GetWCurr());
1006 
1007 	WorkVec.Add(1, TmpDir);
1008 	WorkVec.Add(4, TmpArm.Cross(TmpDir));
1009 	WorkVec.Add(7, Omega.Cross(TmpDir));
1010 	WorkVec.Add(10, (Omega.Cross(TmpArm)).Cross(TmpDir)
1011 		+ TmpArm.Cross(Omega.Cross(TmpDir)));
1012 
1013 	return WorkVec;
1014 }
1015 
1016 /* FollowerForce - end */
1017 
1018 
1019 /* AbsoluteCouple - begin */
1020 
1021 /* Costruttore non banale */
1022 
AbsoluteCouple(unsigned int uL,const StructNode * pN,const TplDriveCaller<Vec3> * pDC,flag fOut)1023 AbsoluteCouple::AbsoluteCouple(unsigned int uL, const StructNode* pN,
1024 	const TplDriveCaller<Vec3>* pDC,
1025 	flag fOut)
1026 : Elem(uL, fOut),
1027 StructuralForce(uL, pN, pDC, fOut)
1028 {
1029 	NO_OP;
1030 }
1031 
1032 
~AbsoluteCouple(void)1033 AbsoluteCouple::~AbsoluteCouple(void)
1034 {
1035 	NO_OP;
1036 }
1037 
1038 
1039 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const1040 AbsoluteCouple::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
1041 {
1042 	*piNumRows = 3;
1043 	*piNumCols = 1;
1044 }
1045 
1046 
1047 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const1048 AbsoluteCouple::InitialWorkSpaceDim(
1049 	integer* piNumRows,
1050 	integer* piNumCols) const
1051 {
1052 	*piNumRows = 3;
1053 	*piNumCols = 1;
1054 }
1055 
1056 
1057 /* Contributo al file di restart */
1058 std::ostream&
Restart(std::ostream & out) const1059 AbsoluteCouple::Restart(std::ostream& out) const
1060 {
1061 	out << "  couple: " << GetLabel() << ", absolute, "
1062 		<< pNode->GetLabel() << ", ";
1063 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
1064 }
1065 
1066 
1067 /* Assembla il residuo */
1068 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)1069 AbsoluteCouple::AssRes(SubVectorHandler& WorkVec,
1070 	doublereal /* dCoef */ ,
1071 	const VectorHandler& /* XCurr */ ,
1072 	const VectorHandler& /* XPrimeCurr */ )
1073 {
1074 	DEBUGCOUT("Entering AbsoluteCouple::AssRes()" << std::endl);
1075 
1076 	integer iNumRows;
1077 	integer iNumCols;
1078 	WorkSpaceDim(&iNumRows, &iNumCols);
1079 	WorkVec.ResizeReset(iNumRows);
1080 
1081 	/* Indici delle incognite del nodo */
1082 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex()+3;
1083 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1084 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex+iCnt);
1085 	}
1086 
1087 	WorkVec.Add(1, f.Get());
1088 
1089 	return WorkVec;
1090 }
1091 
1092 /* Inverse Dynamics*/
1093 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)1094 AbsoluteCouple::AssRes(SubVectorHandler& WorkVec,
1095 	const VectorHandler& /* XCurr */ ,
1096 	const VectorHandler& /* XPrimeCurr */ ,
1097 	const VectorHandler& /* XPrimePrimeCurr */ ,
1098 	InverseDynamics::Order iOrder)
1099 {
1100 	DEBUGCOUT("Entering AbsoluteCouple::AssRes()" << std::endl);
1101 
1102 	integer iNumRows;
1103 	integer iNumCols;
1104 	WorkSpaceDim(&iNumRows, &iNumCols);
1105 	WorkVec.ResizeReset(iNumRows);
1106 
1107 	/* Indici delle incognite del nodo */
1108 	integer iFirstMomentumIndex = pNode->iGetFirstPositionIndex()+3;
1109 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1110 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex+iCnt);
1111 	}
1112 
1113 	WorkVec.Add(1, f.Get());
1114 
1115 	return WorkVec;
1116 }
1117 
1118 void
OutputPrepare(OutputHandler & OH)1119 AbsoluteCouple::OutputPrepare(OutputHandler& OH)
1120 {
1121 	if (bToBeOutput()) {
1122 #ifdef USE_NETCDF
1123 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1124 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
1125 
1126 			std::ostringstream os;
1127 			os << "elem.couple." << GetLabel();
1128 			(void)OH.CreateVar(os.str(), "absolute");
1129 
1130 			// joint sub-data
1131 			os << '.';
1132 			Var_F = OH.CreateVar<Vec3>(os.str() + "M", "Nm",
1133 				"global couple components (x, y, z)");
1134 		}
1135 #endif // USE_NETCDF
1136 	}
1137 }
1138 
1139 
1140 void
Output(OutputHandler & OH) const1141 AbsoluteCouple::Output(OutputHandler& OH) const
1142 {
1143 	if (bToBeOutput()) {
1144 #ifdef USE_NETCDF
1145 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1146 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
1147 		}
1148 #endif // USE_NETCDF
1149 
1150 		if (OH.UseText(OutputHandler::FORCES)) {
1151 			OH.Forces()
1152 				<< GetLabel()
1153 				<< " " << pNode->GetLabel()
1154 				<< " " << f.Get()
1155 				<< std::endl;
1156 		}
1157 
1158 		/* TODO: NetCDF */
1159 	}
1160 }
1161 
1162 
1163 /* Contributo al residuo durante l'assemblaggio iniziale */
1164 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)1165 AbsoluteCouple::InitialAssRes(SubVectorHandler& WorkVec,
1166 	const VectorHandler& /* XCurr */ )
1167 {
1168 	DEBUGCOUT("Entering AbsoluteCouple::InitialAssRes()" << std::endl);
1169 
1170 	WorkVec.Resize(3);
1171 
1172 	/* Indici delle incognite del nodo */
1173 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex() + 3;
1174 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1175 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
1176 	}
1177 
1178 	WorkVec.Add(1, f.Get());
1179 
1180 	return WorkVec;
1181 }
1182 
1183 /* AbsoluteCouple - end */
1184 
1185 
1186 /* FollowerCouple - begin */
1187 
FollowerCouple(unsigned int uL,const StructNode * pN,const TplDriveCaller<Vec3> * pDC,flag fOut)1188 FollowerCouple::FollowerCouple(unsigned int uL, const StructNode* pN,
1189 	const TplDriveCaller<Vec3>* pDC,
1190 	flag fOut)
1191 : Elem(uL, fOut),
1192 StructuralForce(uL, pN, pDC, fOut)
1193 {
1194 	NO_OP;
1195 }
1196 
1197 
~FollowerCouple(void)1198 FollowerCouple::~FollowerCouple(void)
1199 {
1200 	NO_OP;
1201 }
1202 
1203 
1204 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const1205 FollowerCouple::WorkSpaceDim(integer* piNumRows, integer* piNumCols) const
1206 {
1207 	*piNumRows = 3;
1208 	*piNumCols = 3;
1209 }
1210 
1211 
1212 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const1213 FollowerCouple::InitialWorkSpaceDim(
1214 	integer* piNumRows,
1215 	integer* piNumCols) const
1216 {
1217 	*piNumRows = 6;
1218 	*piNumCols = 6;
1219 }
1220 
1221 
1222 /* Contributo al file di restart */
1223 std::ostream&
Restart(std::ostream & out) const1224 FollowerCouple::Restart(std::ostream& out) const
1225 {
1226 	out << "  couple: " << GetLabel() << ", follower, "
1227 		<< pNode->GetLabel() << ", ";
1228 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
1229 }
1230 
1231 
1232 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)1233 FollowerCouple::AssJac(VariableSubMatrixHandler& WorkMat,
1234 	doublereal dCoef,
1235 	const VectorHandler& /* XCurr */ ,
1236 	const VectorHandler& /* XPrimeCurr */ )
1237 {
1238 	DEBUGCOUT("Entering FollowerCouple::AssJac()" << std::endl);
1239 
1240 	FullSubMatrixHandler& WM = WorkMat.SetFull();
1241 
1242 	/* Dimensiona e resetta la matrice di lavoro */
1243 	integer iNumRows = 0;
1244 	integer iNumCols = 0;
1245 	WorkSpaceDim(&iNumRows, &iNumCols);
1246 	WM.ResizeReset(iNumRows, iNumCols);
1247 
1248 	integer iFirstRotationIndex = pNode->iGetFirstPositionIndex() + 3;
1249 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex() + 3;
1250 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1251 		WM.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);    /* coppia */
1252 		WM.PutColIndex(iCnt, iFirstRotationIndex + iCnt);    /* rotazione */
1253 	}
1254 
1255 	/* Dati */
1256 	const Mat3x3& R(pNode->GetRRef());
1257 	Mat3x3 MWedge(MatCross, R*(f.Get()*dCoef));
1258 
1259 	/* | M /\| Delta_g = | M | */
1260 
1261 	WM.Add(1, 1, MWedge);
1262 
1263 	return WorkMat;
1264 }
1265 
1266 
1267 /* Assembla il residuo */
1268 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)1269 FollowerCouple::AssRes(SubVectorHandler& WorkVec,
1270 	doublereal /* dCoef */ ,
1271 	const VectorHandler& /* XCurr */ ,
1272 	const VectorHandler& /* XPrimeCurr */ )
1273 {
1274 	DEBUGCOUT("Entering FollowerCouple::AssRes()" << std::endl);
1275 
1276 	integer iNumRows;
1277 	integer iNumCols;
1278 	WorkSpaceDim(&iNumRows, &iNumCols);
1279 	WorkVec.ResizeReset(iNumRows);
1280 
1281 	/* Indici delle incognite del nodo */
1282 	integer iFirstMomentumIndex = pNode->iGetFirstMomentumIndex() + 3;
1283 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1284 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex + iCnt);
1285 	}
1286 
1287 	/* Dati */
1288 	const Mat3x3& R(pNode->GetRCurr());
1289 	WorkVec.Add(1, R*f.Get());
1290 
1291 	return WorkVec;
1292 }
1293 
1294 
1295 /* Inverse Dynamics*/
1296 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)1297 FollowerCouple::AssRes(SubVectorHandler& WorkVec,
1298 	const VectorHandler& /* XCurr */ ,
1299 	const VectorHandler& /* XPrimeCurr */ ,
1300 	const VectorHandler& /* XPrimePrimeCurr */ ,
1301 	InverseDynamics::Order iOrder)
1302 {
1303 	DEBUGCOUT("Entering FollowerCouple::AssRes()" << std::endl);
1304 
1305 	integer iNumRows;
1306 	integer iNumCols;
1307 	WorkSpaceDim(&iNumRows, &iNumCols);
1308 	WorkVec.ResizeReset(iNumRows);
1309 
1310 	/* Indici delle incognite del nodo */
1311 	integer iFirstMomentumIndex = pNode->iGetFirstPositionIndex()+3;
1312 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1313 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex+iCnt);
1314 	}
1315 
1316 	/* Dati */
1317 	Mat3x3 R(pNode->GetRCurr());
1318 	WorkVec.Add(1, R*f.Get());
1319 
1320 	return WorkVec;
1321 }
1322 
1323 void
OutputPrepare(OutputHandler & OH)1324 FollowerCouple::OutputPrepare(OutputHandler& OH)
1325 {
1326 	if (bToBeOutput()) {
1327 #ifdef USE_NETCDF
1328 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1329 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
1330 
1331 			std::ostringstream os;
1332 			os << "elem.couple." << GetLabel();
1333 			(void)OH.CreateVar(os.str(), "follower");
1334 
1335 			// joint sub-data
1336 			os << '.';
1337 
1338 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
1339 				Var_F = OH.CreateVar<Vec3>(os.str() + "m", "Nm",
1340 					"local couple components (x, y, z)");
1341 
1342 			} else {
1343 				Var_F = OH.CreateVar<Vec3>(os.str() + "M", "Nm",
1344 					"global couple components (x, y, z)");
1345 			}
1346 		}
1347 #endif // USE_NETCDF
1348 	}
1349 }
1350 
1351 
1352 void
Output(OutputHandler & OH) const1353 FollowerCouple::Output(OutputHandler& OH) const
1354 {
1355 	if (bToBeOutput()) {
1356 #ifdef USE_NETCDF
1357 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1358 			if (fToBeOutput() & OUTPUT_REL) {
1359 				Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
1360 			} else {
1361 				Var_F->put_rec((pNode->GetRCurr()*f.Get()).pGetVec(), OH.GetCurrentStep());
1362 			}
1363 		}
1364 #endif // USE_NETCDF
1365 
1366 		if (OH.UseText(OutputHandler::FORCES)) {
1367 			OH.Forces()
1368 				<< GetLabel()
1369 				<< " " << pNode->GetLabel();
1370 			if (fToBeOutput() & OUTPUT_REL) {
1371 				OH.Forces()
1372 					<< " " << f.Get()
1373 					<< std::endl;
1374 
1375 			} else {
1376 				OH.Forces()
1377 					<< " " << pNode->GetRCurr()*f.Get()
1378 					<< std::endl;
1379 			}
1380 		}
1381 	}
1382 }
1383 
1384 
1385 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
1386 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)1387 FollowerCouple::InitialAssJac(VariableSubMatrixHandler& WorkMat,
1388 	const VectorHandler& /* XCurr */ )
1389 {
1390 	DEBUGCOUT("Entering FollowerCouple::InitialAssJac()" << std::endl);
1391 
1392 	FullSubMatrixHandler& WM = WorkMat.SetFull();
1393 
1394 	/* Dimensiona e resetta la matrice di lavoro */
1395 	WM.ResizeReset(6, 6);
1396 
1397 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex() + 3;
1398 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
1399 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1400 		WM.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
1401 		WM.PutRowIndex(3 + iCnt, iFirstVelocityIndex + iCnt);
1402 		WM.PutColIndex(iCnt, iFirstPositionIndex + iCnt);
1403 		WM.PutColIndex(3 + iCnt, iFirstVelocityIndex + iCnt);
1404 	}
1405 
1406 	/* Dati */
1407 	Vec3 TmpDir(pNode->GetRRef()*f.Get());
1408 	const Vec3& Omega(pNode->GetWRef());
1409 
1410 	/* |    F/\   |           |   F  |
1411 	 * |          | Delta_g = |      |
1412 	 * | (d/\F)/\ |           | d/\F |
1413 	 */
1414 
1415 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
1416 	WM.Add(4, 1, Mat3x3(MatCrossCross, Omega, TmpDir));
1417 	WM.Add(4, 4, Mat3x3(MatCross, TmpDir));
1418 
1419 	return WorkMat;
1420 }
1421 
1422 
1423 /* Contributo al residuo durante l'assemblaggio iniziale */
1424 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)1425 FollowerCouple::InitialAssRes(SubVectorHandler& WorkVec,
1426 	const VectorHandler& /* XCurr */ )
1427 {
1428 	DEBUGCOUT("Entering FollowerCouple::InitialAssRes()" << std::endl);
1429 
1430 	WorkVec.ResizeReset(6);
1431 
1432 	/* Indici delle incognite del nodo */
1433 	integer iFirstPositionIndex = pNode->iGetFirstPositionIndex() + 3;
1434 	integer iFirstVelocityIndex = iFirstPositionIndex + 6;
1435 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1436 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex + iCnt);
1437 		WorkVec.PutRowIndex(6 + iCnt, iFirstVelocityIndex + iCnt);
1438 	}
1439 
1440 	/* Dati */
1441 	const Mat3x3& R(pNode->GetRCurr());
1442 	Vec3 TmpDir(R*f.Get());
1443 	const Vec3& Omega(pNode->GetWCurr());
1444 
1445 	WorkVec.Add(1, TmpDir);
1446 	WorkVec.Add(4, Omega.Cross(TmpDir));
1447 
1448 	return WorkVec;
1449 }
1450 
1451 /* FollowerCouple - end */
1452 
1453 
1454 /* StructuralInternalForce - begin */
1455 
1456 /* Costruttore */
StructuralInternalForce(unsigned int uL,const StructNode * pN1,const StructNode * pN2,const TplDriveCaller<Vec3> * pDC,flag fOut)1457 StructuralInternalForce::StructuralInternalForce(unsigned int uL,
1458 	const StructNode* pN1, const StructNode* pN2,
1459 	const TplDriveCaller<Vec3>* pDC,
1460 	flag fOut)
1461 : Elem(uL, fOut),
1462 Force(uL, fOut),
1463 f(pDC),
1464 pNode1(pN1), pNode2(pN2)
1465 #ifdef USE_NETCDF
1466 ,
1467 Var_F(0)
1468 #endif // USE_NETCDF
1469 {
1470 	ASSERT(pNode1 != NULL);
1471 	ASSERT(pNode1->GetNodeType() == Node::STRUCTURAL);
1472 	ASSERT(pNode2 != NULL);
1473 	ASSERT(pNode2->GetNodeType() == Node::STRUCTURAL);
1474 	ASSERT(pDC != NULL);
1475 }
1476 
1477 
~StructuralInternalForce(void)1478 StructuralInternalForce::~StructuralInternalForce(void)
1479 {
1480 	NO_OP;
1481 }
1482 
1483 void
GetConnectedNodes(std::vector<const Node * > & connectedNodes) const1484 StructuralInternalForce::GetConnectedNodes(
1485 	std::vector<const Node *>& connectedNodes) const {
1486 	connectedNodes.resize(2);
1487 	connectedNodes[0] = pNode1;
1488 	connectedNodes[1] = pNode2;
1489 }
1490 
1491 /* StructuralInternalForce - end */
1492 
1493 
1494 /* AbsoluteInternalForce - begin */
1495 
1496 /* Costruttore non banale */
1497 
AbsoluteInternalForce(unsigned int uL,const StructNode * pN1,const StructNode * pN2,const TplDriveCaller<Vec3> * pDC,const Vec3 & TmpArm1,const Vec3 & TmpArm2,flag fOut)1498 AbsoluteInternalForce::AbsoluteInternalForce(unsigned int uL,
1499 	const StructNode* pN1, const StructNode* pN2,
1500 	const TplDriveCaller<Vec3>* pDC,
1501 	const Vec3& TmpArm1, const Vec3& TmpArm2,
1502 	flag fOut)
1503 : Elem(uL, fOut),
1504 StructuralInternalForce(uL, pN1, pN2, pDC, fOut),
1505 Arm1(TmpArm1), Arm2(TmpArm2)
1506 #ifdef USE_NETCDF
1507 ,
1508 Var_A1(0),
1509 Var_A2(0)
1510 #endif // USE_NETCDF
1511 {
1512 	NO_OP;
1513 }
1514 
1515 
~AbsoluteInternalForce(void)1516 AbsoluteInternalForce::~AbsoluteInternalForce(void)
1517 {
1518 	NO_OP;
1519 }
1520 
1521 
1522 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const1523 AbsoluteInternalForce::WorkSpaceDim(
1524 	integer* piNumRows,
1525 	integer* piNumCols) const
1526 {
1527 	*piNumRows = 12;
1528 	*piNumCols = 6;
1529 }
1530 
1531 
1532 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const1533 AbsoluteInternalForce::InitialWorkSpaceDim(
1534 	integer* piNumRows,
1535 	integer* piNumCols) const
1536 {
1537 	*piNumRows = 24;
1538 	*piNumCols = 12;
1539 }
1540 
1541 
1542 /* Contributo al file di restart */
1543 std::ostream&
Restart(std::ostream & out) const1544 AbsoluteInternalForce::Restart(std::ostream& out) const
1545 {
1546 	Force::Restart(out) << ", absolute internal, "
1547 		<< pNode1->GetLabel() << ", position, reference, node, ",
1548 		Arm1.Write(out, ", ") << ", "
1549 		<< pNode2->GetLabel() << ", position, reference, node, ",
1550 		Arm2.Write(out, ", ") << ", ";
1551 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
1552 }
1553 
1554 
1555 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)1556 AbsoluteInternalForce::AssJac(VariableSubMatrixHandler& WorkMat,
1557 	doublereal dCoef,
1558 	const VectorHandler& /* XCurr */ ,
1559 	const VectorHandler& /* XPrimeCurr */ )
1560 {
1561 	DEBUGCOUT("Entering AbsoluteInternalForce::AssJac()" << std::endl);
1562 
1563 	FullSubMatrixHandler& WM = WorkMat.SetFull();
1564 
1565 	/* Dimensiona e resetta la matrice di lavoro */
1566 	WM.ResizeReset(6, 6);
1567 
1568 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex() + 3;
1569 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex() + 3;
1570 
1571 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex() + 3;
1572 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex() + 3;
1573 
1574 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1575 		WM.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
1576 		WM.PutColIndex(iCnt, iFirstPositionIndex1 + iCnt);
1577 
1578 		WM.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
1579 		WM.PutColIndex(3 + iCnt, iFirstPositionIndex2 + iCnt);
1580 	}
1581 
1582 	/* Dati */
1583 	Vec3 TmpArm1(pNode1->GetRRef()*Arm1);
1584 	Vec3 TmpArm2(pNode2->GetRRef()*Arm2);
1585 	Vec3 TmpDir = f.Get()*dCoef;
1586 
1587 	/* |    F/\   |           |   F  |
1588 	 * |          | Delta_g = |      |
1589 	 * | (d/\F)/\ |           | d/\F |
1590 	 */
1591 
1592 	WM.Sub(1, 1, Mat3x3(MatCrossCross, TmpDir, TmpArm1));
1593 	WM.Add(4, 4, Mat3x3(MatCrossCross, TmpDir, TmpArm2));
1594 
1595 	return WorkMat;
1596 }
1597 
1598 
1599 /* Assembla il residuo */
1600 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)1601 AbsoluteInternalForce::AssRes(SubVectorHandler& WorkVec,
1602 	doublereal /* dCoef */ ,
1603 	const VectorHandler& /* XCurr */ ,
1604 	const VectorHandler& /* XPrimeCurr */ )
1605 {
1606 	DEBUGCOUT("Entering AbsoluteInternalForce::AssRes()" << std::endl);
1607 
1608 	integer iNumRows;
1609 	integer iNumCols;
1610 	WorkSpaceDim(&iNumRows, &iNumCols);
1611 	WorkVec.ResizeReset(iNumRows);
1612 
1613 	/* Indici delle incognite del nodo */
1614 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex();
1615 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex();
1616 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
1617 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
1618 		WorkVec.PutRowIndex(6 + iCnt, iFirstMomentumIndex2 + iCnt);
1619 	}
1620 
1621 	/* Dati */
1622 	Vec3 F(f.Get());
1623 	Vec3 M1((pNode1->GetRCurr()*Arm1).Cross(F));
1624 	Vec3 M2(F.Cross(pNode2->GetRCurr()*Arm1));	/* - x2 /\ F */
1625 
1626 	WorkVec.Add(1, F);
1627 	WorkVec.Add(4, M1);
1628 	WorkVec.Sub(7, F);
1629 	WorkVec.Sub(10, M2);
1630 
1631 	return WorkVec;
1632 }
1633 
1634 /* Inverse Dynamics*/
1635 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)1636 AbsoluteInternalForce::AssRes(SubVectorHandler& WorkVec,
1637 	const VectorHandler& /* XCurr */ ,
1638 	const VectorHandler& /* XPrimeCurr */ ,
1639 	const VectorHandler& /* XPrimePrimeCurr */ ,
1640 	InverseDynamics::Order iOrder)
1641 {
1642 	DEBUGCOUT("Entering AbsoluteInternalForce::AssRes()" << std::endl);
1643 
1644 	integer iNumRows;
1645 	integer iNumCols;
1646 	WorkSpaceDim(&iNumRows, &iNumCols);
1647 	WorkVec.ResizeReset(iNumRows);
1648 
1649 	/* Indici delle incognite del nodo */
1650 	integer iFirstMomentumIndex1 = pNode1->iGetFirstPositionIndex();
1651 	integer iFirstMomentumIndex2 = pNode2->iGetFirstPositionIndex();
1652 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
1653 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
1654 		WorkVec.PutRowIndex(6 + iCnt, iFirstMomentumIndex2 + iCnt);
1655 	}
1656 
1657 	/* Dati */
1658 	Vec3 F(f.Get());
1659 	Vec3 M1((pNode1->GetRCurr()*Arm1).Cross(F));
1660 	Vec3 M2(F.Cross(pNode2->GetRCurr()*Arm1));	/* - x2 /\ F */
1661 
1662 	WorkVec.Add(1, F);
1663 	WorkVec.Add(4, M1);
1664 	WorkVec.Sub(7, F);
1665 	WorkVec.Sub(10, M2);
1666 
1667 	return WorkVec;
1668 }
1669 
1670 void
OutputPrepare(OutputHandler & OH)1671 AbsoluteInternalForce::OutputPrepare(OutputHandler& OH)
1672 {
1673 	if (bToBeOutput()) {
1674 #ifdef USE_NETCDF
1675 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1676 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
1677 
1678 			std::ostringstream os;
1679 			os << "elem.force." << GetLabel();
1680 			(void)OH.CreateVar(os.str(), "internal absolute");
1681 
1682 			// joint sub-data
1683 			os << '.';
1684 			Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
1685 				"global force components (x, y, z)");
1686 
1687 			Var_A1 = OH.CreateVar<Vec3>(os.str() + "Arm1", "m",
1688 				"node 1 arm in global frame (x, y, z)");
1689 
1690 			Var_A2 = OH.CreateVar<Vec3>(os.str() + "Arm2", "m",
1691 				"node 2 arm in global frame (x, y, z)");
1692 		}
1693 #endif // USE_NETCDF
1694 	}
1695 }
1696 
1697 void
Output(OutputHandler & OH) const1698 AbsoluteInternalForce::Output(OutputHandler& OH) const
1699 {
1700 	if (bToBeOutput()) {
1701 #ifdef USE_NETCDF
1702 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
1703 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
1704 			Var_A1->put_rec((pNode1->GetXCurr() + pNode1->GetRCurr()*Arm1).pGetVec(), OH.GetCurrentStep());
1705 			Var_A2->put_rec((pNode2->GetXCurr() + pNode2->GetRCurr()*Arm2).pGetVec(), OH.GetCurrentStep());
1706 		}
1707 #endif // USE_NETCDF
1708 
1709 		if (OH.UseText(OutputHandler::FORCES)) {
1710 			Vec3 F(f.Get());
1711 			OH.Forces()
1712 				<< GetLabel()
1713 				<< " " << pNode1->GetLabel()
1714 				<< " " << F
1715 				<< " " << pNode1->GetXCurr() + pNode1->GetRCurr()*Arm1
1716 				<< " " << pNode2->GetLabel()
1717 				<< " " << -F
1718 				<< " " << pNode2->GetXCurr() + pNode2->GetRCurr()*Arm2
1719 				<< std::endl;
1720 		}
1721 
1722 		/* TODO: NetCDF */
1723 	}
1724 }
1725 
1726 
1727 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
1728 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)1729 AbsoluteInternalForce::InitialAssJac(VariableSubMatrixHandler& WorkMat,
1730 	const VectorHandler& /* XCurr */ )
1731 {
1732 	DEBUGCOUT("Entering AbsoluteInternalForce::InitialAssJac()"
1733 		<< std::endl);
1734 
1735 	FullSubMatrixHandler& WM = WorkMat.SetFull();
1736 
1737 	/* Dimensiona e resetta la matrice di lavoro */
1738 	WM.ResizeReset(12, 12);
1739 
1740 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex() + 3;
1741 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
1742 
1743 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex() + 3;
1744 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
1745 
1746 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1747 		WM.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
1748 		WM.PutRowIndex(3 + iCnt, iFirstVelocityIndex1 + iCnt);
1749 
1750 		WM.PutColIndex(iCnt, iFirstPositionIndex1 + iCnt);
1751 		WM.PutColIndex(3 + iCnt, iFirstVelocityIndex1 + iCnt);
1752 
1753 		WM.PutRowIndex(6 + iCnt, iFirstPositionIndex2 + iCnt);
1754 		WM.PutRowIndex(9 + iCnt, iFirstVelocityIndex2 + iCnt);
1755 
1756 		WM.PutColIndex(6 + iCnt, iFirstPositionIndex2 + iCnt);
1757 		WM.PutColIndex(9 + iCnt, iFirstVelocityIndex2 + iCnt);
1758 	}
1759 
1760 	/* Dati */
1761 	Vec3 TmpArm1(pNode1->GetRRef()*Arm1);
1762 	Vec3 TmpArm2(pNode2->GetRRef()*Arm2);
1763 	Vec3 TmpDir = f.Get();
1764 	Vec3 Omega1(pNode1->GetWRef());
1765 	Vec3 Omega2(pNode2->GetWRef());
1766 
1767 	/* |    F/\   |           |   F  |
1768 	 * |          | Delta_g = |      |
1769 	 * | (d/\F)/\ |           | d/\F |
1770 	 */
1771 
1772 	Mat3x3 MTmp(MatCrossCross, TmpDir, TmpArm1);
1773 	WM.Sub(1, 1, MTmp);
1774 	WM.Sub(4, 1, Mat3x3(MatCrossCross, TmpDir, Omega1)*Mat3x3(MatCross, TmpArm1));
1775 	WM.Sub(4, 4, MTmp);
1776 
1777 	MTmp = Mat3x3(MatCrossCross, TmpDir, TmpArm2);
1778 	WM.Add(7, 7, MTmp);
1779 	WM.Add(10, 7, Mat3x3(MatCrossCross, TmpDir, Omega2)*Mat3x3(MatCross, TmpArm2));
1780 	WM.Add(10, 10, MTmp);
1781 
1782 	return WorkMat;
1783 }
1784 
1785 
1786 /* Contributo al residuo durante l'assemblaggio iniziale */
1787 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)1788 AbsoluteInternalForce::InitialAssRes(SubVectorHandler& WorkVec,
1789 	const VectorHandler& /* XCurr */ )
1790 {
1791 	DEBUGCOUT("Entering AbsoluteInternalForce::InitialAssRes()"
1792 		<< std::endl);
1793 
1794 	integer iNumRows;
1795 	integer iNumCols;
1796 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
1797 	WorkVec.ResizeReset(iNumRows);
1798 
1799 	/* Indici delle incognite del nodo */
1800 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex();
1801 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
1802 
1803 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex();
1804 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
1805 
1806 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
1807 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
1808 		WorkVec.PutRowIndex(6 + iCnt, iFirstVelocityIndex1 + iCnt);
1809 
1810 		WorkVec.PutRowIndex(12 + iCnt, iFirstPositionIndex2 + iCnt);
1811 		WorkVec.PutRowIndex(18 + iCnt, iFirstVelocityIndex2 + iCnt);
1812 	}
1813 
1814 	/* Dati */
1815 	Vec3 TmpDir(f.Get());
1816 	Vec3 TmpArm1(pNode1->GetRCurr()*Arm1);
1817 	Vec3 TmpArm2(pNode2->GetRCurr()*Arm2);
1818 	const Vec3& Omega1(pNode1->GetWCurr());
1819 	const Vec3& Omega2(pNode2->GetWCurr());
1820 
1821 	WorkVec.Add(1, TmpDir);
1822 	WorkVec.Add(4, TmpArm1.Cross(TmpDir));
1823 
1824 	/* In 7 non c'e' nulla */
1825 	WorkVec.Add(10, (Omega1.Cross(TmpArm1)).Cross(TmpDir));
1826 
1827 	WorkVec.Sub(7, TmpDir);
1828 	WorkVec.Sub(10, TmpArm2.Cross(TmpDir));
1829 
1830 	/* In 7 non c'e' nulla */
1831 	WorkVec.Sub(16, (Omega2.Cross(TmpArm2)).Cross(TmpDir));
1832 
1833 	return WorkVec;
1834 }
1835 
1836 /* AbsoluteInternalForce - end */
1837 
1838 
1839 /* FollowerInternalForce - begin */
1840 
1841 /* Costruttore non banale */
1842 
FollowerInternalForce(unsigned int uL,const StructNode * pN1,const StructNode * pN2,const TplDriveCaller<Vec3> * pDC,const Vec3 & TmpArm1,const Vec3 & TmpArm2,flag fOut)1843 FollowerInternalForce::FollowerInternalForce(unsigned int uL,
1844 	const StructNode* pN1, const StructNode* pN2,
1845 	const TplDriveCaller<Vec3>* pDC,
1846 	const Vec3& TmpArm1, const Vec3& TmpArm2,
1847 	flag fOut)
1848 : Elem(uL, fOut),
1849 StructuralInternalForce(uL, pN1, pN2, pDC, fOut),
1850 Arm1(TmpArm1), Arm2(TmpArm2)
1851 #ifdef USE_NETCDF
1852 ,
1853 Var_A1(0),
1854 Var_A2(0)
1855 #endif // USE_NETCDF
1856 {
1857 	NO_OP;
1858 }
1859 
1860 
~FollowerInternalForce(void)1861 FollowerInternalForce::~FollowerInternalForce(void)
1862 {
1863 	NO_OP;
1864 }
1865 
1866 
1867 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const1868 FollowerInternalForce::WorkSpaceDim(
1869 	integer* piNumRows,
1870 	integer* piNumCols) const
1871 {
1872 	*piNumRows = 12;
1873 	*piNumCols = 6;
1874 }
1875 
1876 
1877 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const1878 FollowerInternalForce::InitialWorkSpaceDim(
1879 	integer* piNumRows,
1880 	integer* piNumCols) const
1881 {
1882 	*piNumRows = 24;
1883 	*piNumCols = 12;
1884 }
1885 
1886 
1887 /* Contributo al file di restart */
1888 std::ostream&
Restart(std::ostream & out) const1889 FollowerInternalForce::Restart(std::ostream& out) const
1890 {
1891 	Force::Restart(out) << ", follower internal, "
1892 		<< pNode1->GetLabel()
1893 		<< ", position, reference, node, ",
1894 		Arm1.Write(out, ", ") << ", "
1895 		<< pNode2->GetLabel()
1896 		<< ", position, reference, node, ",
1897 		Arm2.Write(out, ", ") << ", ";
1898 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
1899 }
1900 
1901 
1902 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)1903 FollowerInternalForce::AssJac(VariableSubMatrixHandler& WorkMat,
1904 	doublereal dCoef,
1905 	const VectorHandler& /* XCurr */ ,
1906 	const VectorHandler& /* XPrimeCurr */ )
1907 {
1908 	DEBUGCOUT("Entering FollowerInternalForce::AssJac()" << std::endl);
1909 
1910 	FullSubMatrixHandler& WM = WorkMat.SetFull();
1911 
1912 	/* Dimensiona e resetta la matrice di lavoro */
1913 	integer iNumRows = 0;
1914 	integer iNumCols = 0;
1915 	WorkSpaceDim(&iNumRows, &iNumCols);
1916 	WM.ResizeReset(iNumRows, iNumCols);
1917 
1918 	integer iFirstRotationIndex1 = pNode1->iGetFirstPositionIndex() + 3;
1919 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex();
1920 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
1921 		WM.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);     /* forza */
1922 		WM.PutRowIndex(3 + iCnt, iFirstMomentumIndex1 + 3 + iCnt); /* coppia */
1923 		WM.PutColIndex(iCnt, iFirstRotationIndex1 + iCnt);     /* rotazione */
1924 
1925 		WM.PutRowIndex(6 + iCnt, iFirstMomentumIndex1 + iCnt);   /* forza */
1926 		WM.PutRowIndex(9 + iCnt, iFirstMomentumIndex1 + 3 + iCnt); /* coppia */
1927 		WM.PutColIndex(3 + iCnt, iFirstRotationIndex1 + iCnt);   /* rotazione */
1928 	}
1929 
1930 	/* Dati */
1931 	Vec3 TmpDir(pNode1->GetRRef()*(f.Get()*dCoef));
1932 	Vec3 TmpArm1(pNode1->GetRRef()*Arm1);
1933 	Vec3 TmpArm2(pNode2->GetRRef()*Arm2);
1934 
1935 	/* |    F/\       0    |             |   F   |
1936 	 * |                   | Delta_g_1 = |       |
1937 	 * | (d1/\F)/\    0    |             | d1/\F |
1938 	 * |                   | Delta_g_2 = |       |
1939 	 * | -F/\d2/\  d2/\F/\ |             | d2/\F |
1940 	 */
1941 
1942 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
1943 	WM.Add(4, 1, Mat3x3(MatCross, TmpArm1.Cross(TmpDir)));
1944 	WM.Sub(7, 1, Mat3x3(MatCross, TmpDir));
1945 	WM.Sub(7, 1, Mat3x3(MatCrossCross, TmpArm2, TmpDir));
1946 	WM.Add(7, 4, Mat3x3(MatCrossCross, TmpDir, TmpArm2));
1947 
1948 	return WorkMat;
1949 }
1950 
1951 
1952 /* Assembla il residuo */
1953 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)1954 FollowerInternalForce::AssRes(SubVectorHandler& WorkVec,
1955 	doublereal /* dCoef */ ,
1956 	const VectorHandler& /* XCurr */ ,
1957 	const VectorHandler& /* XPrimeCurr */ )
1958 {
1959 	DEBUGCOUT("Entering FollowerInternalForce::AssRes()" << std::endl);
1960 
1961 	integer iNumRows;
1962 	integer iNumCols;
1963 	WorkSpaceDim(&iNumRows, &iNumCols);
1964 	WorkVec.ResizeReset(iNumRows);
1965 
1966 	/* Indici delle incognite del nodo */
1967 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex();
1968 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex();
1969 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
1970 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
1971 		WorkVec.PutRowIndex(6 + iCnt, iFirstMomentumIndex2 + iCnt);
1972 	}
1973 
1974 	/* Dati */
1975 	Vec3 TmpDir(f.Get());
1976 	Vec3 F(pNode1->GetRCurr()*TmpDir);
1977 	Vec3 M1(pNode1->GetRCurr()*Arm1.Cross(TmpDir));
1978 	Vec3 M2(F.Cross(pNode2->GetRCurr()*Arm2));
1979 
1980 	WorkVec.Add(1, F);
1981 	WorkVec.Add(4, M1);
1982 	WorkVec.Sub(7, F);
1983 	WorkVec.Add(10, M2);
1984 
1985 	return WorkVec;
1986 }
1987 
1988 /* Inverse Dynamics*/
1989 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)1990 FollowerInternalForce::AssRes(SubVectorHandler& WorkVec,
1991 	const VectorHandler& /* XCurr */ ,
1992 	const VectorHandler& /* XPrimeCurr */ ,
1993 	const VectorHandler& /* XPrimePrimeCurr */ ,
1994 	InverseDynamics::Order iOrder)
1995 {
1996 	DEBUGCOUT("Entering FollowerInternalForce::AssRes()" << std::endl);
1997 
1998 	integer iNumRows;
1999 	integer iNumCols;
2000 	WorkSpaceDim(&iNumRows, &iNumCols);
2001 	WorkVec.ResizeReset(iNumRows);
2002 
2003 	/* Indici delle incognite del nodo */
2004 	integer iFirstMomentumIndex1 = pNode1->iGetFirstPositionIndex();
2005 	integer iFirstMomentumIndex2 = pNode2->iGetFirstPositionIndex();
2006 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
2007 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
2008 		WorkVec.PutRowIndex(6+iCnt, iFirstMomentumIndex2 + iCnt);
2009 	}
2010 
2011 	/* Dati */
2012 	Vec3 TmpDir(f.Get());
2013 	Vec3 F(pNode1->GetRCurr()*TmpDir);
2014 	Vec3 M1(pNode1->GetRCurr()*Arm1.Cross(TmpDir));
2015 	Vec3 M2(F.Cross(pNode2->GetRCurr()*Arm2));
2016 
2017 	WorkVec.Add(1, F);
2018 	WorkVec.Add(4, M1);
2019 	WorkVec.Sub(7, F);
2020 	WorkVec.Add(10, M2);
2021 
2022 	return WorkVec;
2023 }
2024 
2025 void
OutputPrepare(OutputHandler & OH)2026 FollowerInternalForce::OutputPrepare(OutputHandler& OH)
2027 {
2028 	if (bToBeOutput()) {
2029 #ifdef USE_NETCDF
2030 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2031 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
2032 
2033 			std::ostringstream os;
2034 			os << "elem.force." << GetLabel();
2035 			(void)OH.CreateVar(os.str(), "internal follower");
2036 
2037 			// joint sub-data
2038 			os << '.';
2039 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2040 				Var_F = OH.CreateVar<Vec3>(os.str() + "f", "N",
2041 					"local force components (x, y, z)");
2042 			} else {
2043 				Var_F = OH.CreateVar<Vec3>(os.str() + "F", "N",
2044 					"global force components (x, y, z)");
2045 			}
2046 
2047 			Var_A1 = OH.CreateVar<Vec3>(os.str() + "Arm1", "m",
2048 				"node 1 arm in global frame (x, y, z)");
2049 
2050 			Var_A2 = OH.CreateVar<Vec3>(os.str() + "Arm2", "m",
2051 				"node 2 arm in global frame (x, y, z)");
2052 		}
2053 #endif // USE_NETCDF
2054 	}
2055 }
2056 
2057 void
Output(OutputHandler & OH) const2058 FollowerInternalForce::Output(OutputHandler& OH) const
2059 {
2060 	if (bToBeOutput()) {
2061 #ifdef USE_NETCDF
2062 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2063 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2064 				Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
2065 			} else {
2066 				Var_F->put_rec((pNode1->GetRCurr()*f.Get()).pGetVec(), OH.GetCurrentStep());
2067 			}
2068 			Var_A1->put_rec((pNode1->GetXCurr() + pNode1->GetRCurr()*Arm1).pGetVec(), OH.GetCurrentStep());
2069 			Var_A2->put_rec((pNode2->GetXCurr() + pNode2->GetRCurr()*Arm2).pGetVec(), OH.GetCurrentStep());
2070 		}
2071 #endif // USE_NETCDF
2072 
2073 		if (OH.UseText(OutputHandler::FORCES)) {
2074 			Vec3 F;
2075 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2076 				F = f.Get();
2077 			} else {
2078 				F = pNode1->GetRCurr()*f.Get();
2079 			}
2080 
2081 			OH.Forces()
2082 				<< GetLabel()
2083 				<< " " << pNode1->GetLabel()
2084 				<< " " << F
2085 				<< " " << pNode1->GetXCurr() + pNode1->GetRCurr()*Arm1
2086 				<< " " << pNode2->GetLabel()
2087 				<< " " << -F
2088 				<< " " << pNode2->GetXCurr() + pNode2->GetRCurr()*Arm2
2089 				<< std::endl;
2090 		}
2091 
2092 		/* TODO: NetCDF */
2093 	}
2094 }
2095 
2096 
2097 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
2098 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)2099 FollowerInternalForce::InitialAssJac(VariableSubMatrixHandler& WorkMat,
2100 	const VectorHandler& /* XCurr */ )
2101 {
2102 	DEBUGCOUT("Entering FollowerInternalForce::InitialAssJac()" << std::endl);
2103 
2104 	FullSubMatrixHandler& WM = WorkMat.SetFull();
2105 
2106 	integer iNumRows;
2107 	integer iNumCols;
2108 	WorkSpaceDim(&iNumRows, &iNumCols);
2109 
2110 	/* Dimensiona e resetta la matrice di lavoro */
2111 	WM.ResizeReset(iNumRows, iNumCols);
2112 
2113 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex();
2114 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
2115 
2116 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex();
2117 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
2118 
2119 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2120 		WM.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
2121 		WM.PutRowIndex(3 + iCnt, iFirstPositionIndex1 + 3 + iCnt);
2122 		WM.PutRowIndex(6 + iCnt, iFirstVelocityIndex1 + iCnt);
2123 		WM.PutRowIndex(9 + iCnt, iFirstVelocityIndex1 + 3 + iCnt);
2124 
2125 		WM.PutColIndex(iCnt, iFirstPositionIndex1 +3+iCnt);
2126 		WM.PutColIndex(3 + iCnt, iFirstVelocityIndex1 + 3 + iCnt);
2127 
2128 		WM.PutRowIndex(12 + iCnt, iFirstPositionIndex2 + iCnt);
2129 		WM.PutRowIndex(15 + iCnt, iFirstPositionIndex2 + 3 + iCnt);
2130 		WM.PutRowIndex(18 + iCnt, iFirstVelocityIndex2 + iCnt);
2131 		WM.PutRowIndex(21 + iCnt, iFirstVelocityIndex2 + 3 + iCnt);
2132 
2133 		WM.PutColIndex(12 + iCnt, iFirstPositionIndex2 + 3 + iCnt);
2134 		WM.PutColIndex(15 + iCnt, iFirstVelocityIndex2 + 3 + iCnt);
2135 	}
2136 
2137 	/* Dati */
2138 	Vec3 TmpArm1(pNode1->GetRRef()*Arm1);
2139 	Vec3 TmpArm2(pNode2->GetRRef()*Arm2);
2140 	Vec3 TmpDir = pNode1->GetRRef()*f.Get();
2141 	const Vec3& Omega1(pNode1->GetWRef());
2142 	const Vec3& Omega2(pNode2->GetWRef());
2143 
2144 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
2145 	WM.Add(4, 1, Mat3x3(MatCross, TmpArm1.Cross(TmpDir)));
2146 
2147 	WM.Add(7, 1, Mat3x3(MatCrossCross, Omega1, TmpDir));
2148 	WM.Add(7, 4, Mat3x3(MatCross, TmpDir));
2149 	WM.Add(10, 1, Mat3x3(MatCrossCross, Omega1, TmpArm1.Cross(TmpDir)));
2150 	WM.Add(10, 4, Mat3x3(MatCross, TmpArm1.Cross(TmpDir)));
2151 
2152 	WM.Sub(13, 1, Mat3x3(MatCross, TmpDir));
2153 	WM.Add(16, 1, Mat3x3(MatCrossCross, TmpArm2, TmpDir));
2154 	WM.Sub(16, 7, Mat3x3(MatCrossCross, TmpDir, TmpArm2));
2155 
2156 	WM.Sub(19, 1, Mat3x3(MatCrossCross, Omega1, TmpDir));
2157 	WM.Sub(19, 4, Mat3x3(MatCross, TmpDir));
2158 
2159 	WM.Add(22, 1, Mat3x3(MatCrossCross, TmpArm2, Omega1)*Mat3x3(MatCross, TmpDir)
2160 		- Mat3x3(MatCrossCross, Omega2.Cross(TmpArm2), TmpDir));
2161 	WM.Add(22, 4, Mat3x3(MatCrossCross, TmpArm2, TmpDir));
2162 	WM.Add(22, 7, Mat3x3(MatCrossCross, TmpDir, Omega2)*Mat3x3(MatCross, TmpArm2)
2163 		- Mat3x3(MatCrossCross, Omega1.Cross(TmpDir), TmpArm2));
2164 	WM.Add(22, 10, Mat3x3(MatCrossCross, TmpDir, TmpArm2));
2165 
2166 	return WorkMat;
2167 }
2168 
2169 
2170 /* Contributo al residuo durante l'assemblaggio iniziale */
2171 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)2172 FollowerInternalForce::InitialAssRes(SubVectorHandler& WorkVec,
2173 	const VectorHandler& /* XCurr */ )
2174 {
2175 	DEBUGCOUT("Entering FollowerInternalForce::InitialAssRes()" << std::endl);
2176 
2177 	integer iNumRows;
2178 	integer iNumCols;
2179 	InitialWorkSpaceDim(&iNumRows, &iNumCols);
2180 	WorkVec.ResizeReset(iNumRows);
2181 
2182 	/* Indici delle incognite del nodo */
2183 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex();
2184 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
2185 
2186 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex();
2187 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
2188 
2189 	for (integer iCnt = 1; iCnt <= 6; iCnt++) {
2190 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
2191 		WorkVec.PutRowIndex(6 + iCnt, iFirstVelocityIndex1 + iCnt);
2192 
2193 		WorkVec.PutRowIndex(12 + iCnt, iFirstPositionIndex2 + iCnt);
2194 		WorkVec.PutRowIndex(18 + iCnt, iFirstVelocityIndex2 + iCnt);
2195 	}
2196 
2197 	/* Dati */
2198 	Vec3 TmpDir(pNode1->GetRCurr()*f.Get());
2199 	Vec3 TmpArm1(pNode1->GetRCurr()*Arm1);
2200 	Vec3 TmpArm2(pNode2->GetRCurr()*Arm2);
2201 	const Vec3& Omega1(pNode1->GetWCurr());
2202 	const Vec3& Omega2(pNode2->GetWCurr());
2203 
2204 	WorkVec.Add(1, TmpDir);
2205 	WorkVec.Add(4, TmpArm1.Cross(TmpDir));
2206 	WorkVec.Add(7, Omega1.Cross(TmpDir));
2207 	WorkVec.Add(10, (Omega1.Cross(TmpArm1)).Cross(TmpDir)
2208 		+ TmpArm1.Cross(Omega1.Cross(TmpDir)));
2209 
2210 	WorkVec.Sub(13, TmpDir);
2211 	WorkVec.Sub(16, TmpArm2.Cross(TmpDir));
2212 	WorkVec.Sub(19, Omega1.Cross(TmpDir));
2213 	WorkVec.Sub(22, (Omega2.Cross(TmpArm2)).Cross(TmpDir)
2214 		+ TmpArm2.Cross(Omega1.Cross(TmpDir)));
2215 
2216 	return WorkVec;
2217 }
2218 
2219 /* FollowerInternalForce - end */
2220 
2221 
2222 /* AbsoluteInternalCouple - begin */
2223 
2224 /* Costruttore non banale */
2225 
AbsoluteInternalCouple(unsigned int uL,const StructNode * pN1,const StructNode * pN2,const TplDriveCaller<Vec3> * pDC,flag fOut)2226 AbsoluteInternalCouple::AbsoluteInternalCouple(unsigned int uL,
2227 	const StructNode* pN1, const StructNode* pN2,
2228 	const TplDriveCaller<Vec3>* pDC,
2229 	flag fOut)
2230 : Elem(uL, fOut),
2231 StructuralInternalForce(uL, pN1, pN2, pDC, fOut)
2232 {
2233 	NO_OP;
2234 }
2235 
2236 
~AbsoluteInternalCouple(void)2237 AbsoluteInternalCouple::~AbsoluteInternalCouple(void)
2238 {
2239 	NO_OP;
2240 }
2241 
2242 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const2243 AbsoluteInternalCouple::WorkSpaceDim(
2244 	integer* piNumRows,
2245 	integer* piNumCols) const
2246 {
2247 	*piNumRows = 6;
2248 	*piNumCols = 1;
2249 }
2250 
2251 
2252 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const2253 AbsoluteInternalCouple::InitialWorkSpaceDim(
2254 	integer* piNumRows,
2255 	integer* piNumCols) const
2256 {
2257 	*piNumRows = 6;
2258 	*piNumCols = 1;
2259 }
2260 
2261 
2262 /* Contributo al file di restart */
2263 std::ostream&
Restart(std::ostream & out) const2264 AbsoluteInternalCouple::Restart(std::ostream& out) const
2265 {
2266 	out << "  couple: " << GetLabel() << ", absolute internal, "
2267 		<< pNode1->GetLabel() << ", "
2268 		<< pNode2->GetLabel() << ", ";
2269 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
2270 }
2271 
2272 
2273 /* Assembla il residuo */
2274 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)2275 AbsoluteInternalCouple::AssRes(SubVectorHandler& WorkVec,
2276 	doublereal /* dCoef */ ,
2277 	const VectorHandler& /* XCurr */ ,
2278 	const VectorHandler& /* XPrimeCurr */ )
2279 {
2280 	DEBUGCOUT("Entering AbsoluteInternalCouple::AssRes()" << std::endl);
2281 
2282 	integer iNumRows;
2283 	integer iNumCols;
2284 	WorkSpaceDim(&iNumRows, &iNumCols);
2285 	WorkVec.ResizeReset(iNumRows);
2286 
2287 	/* Indici delle incognite del nodo */
2288 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex() + 3;
2289 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex() + 3;
2290 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2291 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
2292 		WorkVec.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
2293 	}
2294 
2295 	/* Dati */
2296 	Vec3 F(f.Get());
2297 
2298 	WorkVec.Add(1, F);
2299 	WorkVec.Sub(4, F);
2300 
2301 	return WorkVec;
2302 }
2303 
2304 /* Inverse Dynamics*/
2305 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)2306 AbsoluteInternalCouple::AssRes(SubVectorHandler& WorkVec,
2307 	const VectorHandler& /* XCurr */ ,
2308 	const VectorHandler& /* XPrimeCurr */ ,
2309 	const VectorHandler& /* XPrimePrimeCurr */ ,
2310 	InverseDynamics::Order iOrder)
2311 {
2312 	DEBUGCOUT("Entering AbsoluteInternalCouple::AssRes()" << std::endl);
2313 
2314 	integer iNumRows;
2315 	integer iNumCols;
2316 	WorkSpaceDim(&iNumRows, &iNumCols);
2317 	WorkVec.ResizeReset(iNumRows);
2318 
2319 	/* Indici delle incognite del nodo */
2320 	integer iFirstMomentumIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2321 	integer iFirstMomentumIndex2 = pNode2->iGetFirstPositionIndex() + 3;
2322 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2323 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
2324 		WorkVec.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
2325 	}
2326 
2327 	/* Dati */
2328 	Vec3 F(f.Get());
2329 
2330 	WorkVec.Add(1, F);
2331 	WorkVec.Sub(4, F);
2332 
2333 	return WorkVec;
2334 }
2335 
2336 void
OutputPrepare(OutputHandler & OH)2337 AbsoluteInternalCouple::OutputPrepare(OutputHandler& OH)
2338 {
2339 	if (bToBeOutput()) {
2340 #ifdef USE_NETCDF
2341 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2342 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
2343 
2344 			std::ostringstream os;
2345 			os << "elem.couple." << GetLabel();
2346 			(void)OH.CreateVar(os.str(), "internal absolute");
2347 
2348 			// joint sub-data
2349 			os << '.';
2350 			Var_F = OH.CreateVar<Vec3>(os.str() + "M", "Nm",
2351 				"global couple components (x, y, z)");
2352 		}
2353 #endif // USE_NETCDF
2354 	}
2355 }
2356 
2357 void
Output(OutputHandler & OH) const2358 AbsoluteInternalCouple::Output(OutputHandler& OH) const
2359 {
2360 	if (bToBeOutput()) {
2361 #ifdef USE_NETCDF
2362 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2363 			Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
2364 		}
2365 #endif // USE_NETCDF
2366 
2367 		if (OH.UseText(OutputHandler::FORCES)) {
2368 			Vec3 F(f.Get());
2369 			OH.Forces()
2370 				<< GetLabel()
2371 				<< " " << pNode1->GetLabel()
2372 				<< " " << F
2373 				<< " " << pNode2->GetLabel()
2374 				<< " " << -F
2375 				<< std::endl;
2376 		}
2377 
2378 		/* TODO: NetCDF */
2379 	}
2380 }
2381 
2382 
2383 /* Contributo al residuo durante l'assemblaggio iniziale */
2384 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)2385 AbsoluteInternalCouple::InitialAssRes(SubVectorHandler& WorkVec,
2386 	const VectorHandler& /* XCurr */ )
2387 {
2388 	DEBUGCOUT("Entering AbsoluteInternalCouple::InitialAssRes()" << std::endl);
2389 
2390 	WorkVec.ResizeReset(6);
2391 
2392 	/* Indici delle incognite del nodo */
2393 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2394 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex() + 3;
2395 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2396 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
2397 		WorkVec.PutRowIndex(3 + iCnt, iFirstPositionIndex2 + iCnt);
2398 	}
2399 
2400 	/* Dati */
2401 	Vec3 F(f.Get());
2402 
2403 	WorkVec.Add(1, F);
2404 	WorkVec.Sub(4, F);
2405 
2406 	return WorkVec;
2407 }
2408 
2409 /* AbsoluteInternalCouple - end */
2410 
2411 
2412 /* FollowerInternalCouple - begin */
2413 
FollowerInternalCouple(unsigned int uL,const StructNode * pN1,const StructNode * pN2,const TplDriveCaller<Vec3> * pDC,flag fOut)2414 FollowerInternalCouple::FollowerInternalCouple(unsigned int uL,
2415 	const StructNode* pN1, const StructNode* pN2,
2416 	const TplDriveCaller<Vec3>* pDC,
2417 	flag fOut)
2418 : Elem(uL, fOut),
2419 StructuralInternalForce(uL, pN1, pN2, pDC, fOut)
2420 {
2421 	NO_OP;
2422 }
2423 
2424 
~FollowerInternalCouple(void)2425 FollowerInternalCouple::~FollowerInternalCouple(void)
2426 {
2427 	NO_OP;
2428 }
2429 
2430 void
WorkSpaceDim(integer * piNumRows,integer * piNumCols) const2431 FollowerInternalCouple::WorkSpaceDim(
2432 	integer* piNumRows,
2433 	integer* piNumCols) const
2434 {
2435 	*piNumRows = 6;
2436 	*piNumCols = 3;
2437 }
2438 
2439 
2440 void
InitialWorkSpaceDim(integer * piNumRows,integer * piNumCols) const2441 FollowerInternalCouple::InitialWorkSpaceDim(
2442 	integer* piNumRows,
2443 	integer* piNumCols) const
2444 {
2445 	*piNumRows = 12;
2446 	*piNumCols = 12;
2447 }
2448 
2449 
2450 /* Contributo al file di restart */
2451 std::ostream&
Restart(std::ostream & out) const2452 FollowerInternalCouple::Restart(std::ostream& out) const
2453 {
2454 	out << "  couple: " << GetLabel() << ", follower internal, "
2455 		<< pNode1->GetLabel() << ", "
2456 		<< pNode2->GetLabel() << ", ";
2457 	return f.pGetDriveCaller()->Restart(out) << ';' << std::endl;
2458 }
2459 
2460 
2461 VariableSubMatrixHandler&
AssJac(VariableSubMatrixHandler & WorkMat,doublereal dCoef,const VectorHandler &,const VectorHandler &)2462 FollowerInternalCouple::AssJac(VariableSubMatrixHandler& WorkMat,
2463 	doublereal dCoef,
2464 	const VectorHandler& /* XCurr */ ,
2465 	const VectorHandler& /* XPrimeCurr */ )
2466 {
2467 	DEBUGCOUT("Entering FollowerInternalCouple::AssJac()" << std::endl);
2468 
2469 	FullSubMatrixHandler& WM = WorkMat.SetFull();
2470 
2471 	/* Dimensiona e resetta la matrice di lavoro */
2472 	integer iNumRows = 0;
2473 	integer iNumCols = 0;
2474 	WorkSpaceDim(&iNumRows, &iNumCols);
2475 	WM.ResizeReset(iNumRows, iNumCols);
2476 
2477 	integer iFirstRotationIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2478 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex() + 3;
2479 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex() + 3;
2480 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2481 		WM.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);    /* coppia */
2482 		WM.PutColIndex(iCnt, iFirstRotationIndex1 + iCnt);    /* rotazione */
2483 
2484 		WM.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);    /* coppia */
2485 	}
2486 
2487 	/* Dati */
2488 	Mat3x3 MWedge(MatCross, pNode1->GetRRef()*(f.Get()*dCoef));
2489 
2490 	/* | M /\| Delta_g = | M | */
2491 
2492 	WM.Add(1, 1, MWedge);
2493 	WM.Sub(4, 1, MWedge);
2494 
2495 	return WorkMat;
2496 }
2497 
2498 
2499 /* Assembla il residuo */
2500 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,doublereal,const VectorHandler &,const VectorHandler &)2501 FollowerInternalCouple::AssRes(SubVectorHandler& WorkVec,
2502 	doublereal /* dCoef */ ,
2503 	const VectorHandler& /* XCurr */ ,
2504 	const VectorHandler& /* XPrimeCurr */ )
2505 {
2506 	DEBUGCOUT("Entering FollowerInternalCouple::AssRes()" << std::endl);
2507 
2508 	integer iNumRows;
2509 	integer iNumCols;
2510 	WorkSpaceDim(&iNumRows, &iNumCols);
2511 	WorkVec.ResizeReset(iNumRows);
2512 
2513 	/* Indici delle incognite del nodo */
2514 	integer iFirstMomentumIndex1 = pNode1->iGetFirstMomentumIndex() + 3;
2515 	integer iFirstMomentumIndex2 = pNode2->iGetFirstMomentumIndex() + 3;
2516 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2517 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
2518 		WorkVec.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
2519 	}
2520 
2521 	/* Dati */
2522 	Vec3 M(pNode1->GetRCurr()*f.Get());
2523 
2524 	WorkVec.Add(1, M);
2525 	WorkVec.Sub(4, M);
2526 
2527 	return WorkVec;
2528 }
2529 
2530 /* Inverse Dynamics*/
2531 SubVectorHandler&
AssRes(SubVectorHandler & WorkVec,const VectorHandler &,const VectorHandler &,const VectorHandler &,InverseDynamics::Order iOrder)2532 FollowerInternalCouple::AssRes(SubVectorHandler& WorkVec,
2533 	const VectorHandler& /* XCurr */ ,
2534 	const VectorHandler& /* XPrimeCurr */ ,
2535 	const VectorHandler& /* XPrimePrimeCurr */ ,
2536 	InverseDynamics::Order iOrder)
2537 {
2538 	DEBUGCOUT("Entering FollowerInternalCouple::AssRes()" << std::endl);
2539 
2540 	integer iNumRows;
2541 	integer iNumCols;
2542 	WorkSpaceDim(&iNumRows, &iNumCols);
2543 	WorkVec.ResizeReset(iNumRows);
2544 
2545 	/* Indici delle incognite del nodo */
2546 	integer iFirstMomentumIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2547 	integer iFirstMomentumIndex2 = pNode2->iGetFirstPositionIndex() + 3;
2548 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2549 		WorkVec.PutRowIndex(iCnt, iFirstMomentumIndex1 + iCnt);
2550 		WorkVec.PutRowIndex(3 + iCnt, iFirstMomentumIndex2 + iCnt);
2551 	}
2552 
2553 	/* Dati */
2554 	Vec3 M(pNode1->GetRCurr()*f.Get());
2555 
2556 	WorkVec.Add(1, M);
2557 	WorkVec.Sub(4, M);
2558 
2559 	return WorkVec;
2560 }
2561 
2562 void
OutputPrepare(OutputHandler & OH)2563 FollowerInternalCouple::OutputPrepare(OutputHandler& OH)
2564 {
2565 	if (bToBeOutput()) {
2566 #ifdef USE_NETCDF
2567 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2568 			ASSERT(OH.IsOpen(OutputHandler::NETCDF));
2569 
2570 			std::ostringstream os;
2571 			os << "elem.couple." << GetLabel();
2572 			(void)OH.CreateVar(os.str(), "internal follower");
2573 
2574 			// joint sub-data
2575 			os << '.';
2576 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2577 				Var_F = OH.CreateVar<Vec3>(os.str() + "m", "Nm",
2578 					"local couple components (x, y, z)");
2579 
2580 			} else {
2581 				Var_F = OH.CreateVar<Vec3>(os.str() + "M", "Nm",
2582 					"global couple components (x, y, z)");
2583 			}
2584 		}
2585 #endif // USE_NETCDF
2586 	}
2587 }
2588 
2589 void
Output(OutputHandler & OH) const2590 FollowerInternalCouple::Output(OutputHandler& OH) const
2591 {
2592 	if (bToBeOutput()) {
2593 #ifdef USE_NETCDF
2594 		if (OH.UseNetCDF(OutputHandler::FORCES)) {
2595 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2596 				Var_F->put_rec(f.Get().pGetVec(), OH.GetCurrentStep());
2597 			} else {
2598 				Var_F->put_rec((pNode1->GetRCurr()*f.Get()).pGetVec(), OH.GetCurrentStep());
2599 			}
2600 		}
2601 #endif // USE_NETCDF
2602 
2603 		if (OH.UseText(OutputHandler::FORCES)) {
2604 			Vec3 F;
2605 			if (fToBeOutput() & StructuralForce::OUTPUT_REL) {
2606 				F = f.Get();
2607 			} else {
2608 				F = pNode1->GetRCurr()*f.Get();
2609 			}
2610 
2611 			OH.Forces()
2612 				<< GetLabel()
2613 				<< " " << pNode1->GetLabel()
2614 				<< " " << F
2615 				<< " " << pNode2->GetLabel()
2616 				<< " " << -F
2617 				<< std::endl;
2618 		}
2619 
2620 		/* TODO: NetCDF */
2621 	}
2622 }
2623 
2624 
2625 /* Contributo allo jacobiano durante l'assemblaggio iniziale */
2626 VariableSubMatrixHandler&
InitialAssJac(VariableSubMatrixHandler & WorkMat,const VectorHandler &)2627 FollowerInternalCouple::InitialAssJac(VariableSubMatrixHandler& WorkMat,
2628 	const VectorHandler& /* XCurr */ )
2629 {
2630 	DEBUGCOUT("Entering FollowerInternalCouple::InitialAssJac()" << std::endl);
2631 
2632 	FullSubMatrixHandler& WM = WorkMat.SetFull();
2633 
2634 	/* Dimensiona e resetta la matrice di lavoro */
2635 	WM.ResizeReset(12, 6);
2636 
2637 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2638 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
2639 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex() + 3;
2640 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
2641 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2642 		WM.PutRowIndex(iCnt, iFirstPositionIndex1 + iCnt);
2643 		WM.PutRowIndex(3 + iCnt, iFirstVelocityIndex1 + iCnt);
2644 
2645 		WM.PutColIndex(iCnt, iFirstPositionIndex1 + iCnt);
2646 		WM.PutColIndex(3 + iCnt, iFirstVelocityIndex1 + iCnt);
2647 
2648 		WM.PutRowIndex(6 + iCnt, iFirstPositionIndex2 + iCnt);
2649 		WM.PutRowIndex(9 + iCnt, iFirstVelocityIndex2 + iCnt);
2650 	}
2651 
2652 	/* Dati */
2653 	Vec3 TmpDir(pNode1->GetRRef()*f.Get());
2654 	const Vec3& Omega1(pNode1->GetWRef());
2655 
2656 	/* |    F/\   |           |   F  |
2657 	 * |          | Delta_g = |      |
2658 	 * | (d/\F)/\ |           | d/\F |
2659 	 */
2660 
2661 	WM.Add(1, 1, Mat3x3(MatCross, TmpDir));
2662 	WM.Add(4, 1, Mat3x3(MatCrossCross, Omega1, TmpDir));
2663 	WM.Add(4, 4, Mat3x3(MatCross, TmpDir));
2664 
2665 	WM.Sub(7, 1, Mat3x3(MatCross, TmpDir));
2666 	WM.Sub(10, 1, Mat3x3(MatCrossCross, Omega1, TmpDir));
2667 	WM.Sub(10, 4, Mat3x3(MatCross, TmpDir));
2668 
2669 	return WorkMat;
2670 }
2671 
2672 
2673 /* Contributo al residuo durante l'assemblaggio iniziale */
2674 SubVectorHandler&
InitialAssRes(SubVectorHandler & WorkVec,const VectorHandler &)2675 FollowerInternalCouple::InitialAssRes(SubVectorHandler& WorkVec,
2676 	const VectorHandler& /* XCurr */ )
2677 {
2678 	DEBUGCOUT("Entering FollowerInternalCouple::InitialAssRes()" << std::endl);
2679 
2680 	WorkVec.ResizeReset(12);
2681 
2682 	/* Indici delle incognite del nodo */
2683 	integer iFirstPositionIndex1 = pNode1->iGetFirstPositionIndex() + 3;
2684 	integer iFirstVelocityIndex1 = iFirstPositionIndex1 + 6;
2685 
2686 	integer iFirstPositionIndex2 = pNode2->iGetFirstPositionIndex() + 3;
2687 	integer iFirstVelocityIndex2 = iFirstPositionIndex2 + 6;
2688 
2689 	for (integer iCnt = 1; iCnt <= 3; iCnt++) {
2690 		WorkVec.PutRowIndex(iCnt, iFirstPositionIndex1+iCnt);
2691 		WorkVec.PutRowIndex(3 + iCnt, iFirstVelocityIndex1 + iCnt);
2692 
2693 		WorkVec.PutRowIndex(6 + iCnt, iFirstPositionIndex2 + iCnt);
2694 		WorkVec.PutRowIndex(9 + iCnt, iFirstVelocityIndex2 + iCnt);
2695 	}
2696 
2697 	/* Dati */
2698 	Vec3 TmpDir(pNode1->GetRCurr()*f.Get());
2699 	const Vec3& Omega1(pNode1->GetWCurr());
2700 
2701 	WorkVec.Add(1, TmpDir);
2702 	WorkVec.Add(4, Omega1.Cross(TmpDir));
2703 
2704 	WorkVec.Sub(7, TmpDir);
2705 	WorkVec.Sub(10, Omega1.Cross(TmpDir));
2706 
2707 	return WorkVec;
2708 }
2709 
2710 /* FollowerInternalCouple - end */
2711 
2712 Elem *
ReadStructuralForce(DataManager * pDM,MBDynParser & HP,unsigned int uLabel,bool bDisp,bool bCouple,bool bFollower,bool bInternal)2713 ReadStructuralForce(DataManager* pDM,
2714 	MBDynParser& HP,
2715 	unsigned int uLabel,
2716 	bool bDisp,
2717 	bool bCouple,
2718 	bool bFollower,
2719 	bool bInternal)
2720 {
2721 	Elem *pEl = 0;
2722 	const char *sType = bCouple ? "Couple" : "Force";
2723 
2724 	/* nodo collegato */
2725 	const StructDispNode* pDispNode = pDM->ReadNode<const StructDispNode, Node::STRUCTURAL>(HP);
2726 	const StructNode* pNode = dynamic_cast<const StructNode *>(pDispNode);
2727 	ReferenceFrame rf;
2728 	if (pNode) {
2729 		rf = ReferenceFrame(pNode);
2730 	}
2731 	Vec3 Arm(Zero3);
2732 
2733 	// FIXME: legacy...
2734 	Vec3 Dir(Zero3);
2735 	bool bLegacy(false);
2736 	bool bGotPosition(false);
2737 
2738 	/* distanza dal nodo (vettore di 3 elementi) (solo se e' una forza) */
2739 	if (!bDisp) {
2740 		if (pNode == 0) {
2741 			silent_cerr(sType << "(" << uLabel << "): "
2742 				"invalid node type at line " << HP.GetLineData() << std::endl);
2743 			throw ErrGeneric(MBDYN_EXCEPT_ARGS);
2744 		}
2745 
2746 		if (HP.IsKeyWord("position")) {
2747 			Arm = HP.GetPosRel(rf);
2748 			bGotPosition = true;
2749 			DEBUGCOUT("Arm is supplied" << std::endl);
2750 
2751 		} else {
2752 			if (!bCouple) {
2753 				silent_cerr(sType << "(" << uLabel << "): "
2754 					"\"position\" keyword expected "
2755 					"at line " << HP.GetLineData() << "; "
2756 					"still using deprecated syntax?"
2757 					<< std::endl);
2758 
2759 				if (bFollower) {
2760 					try {
2761 						Dir = HP.GetUnitVecRel(rf);
2762 					} catch (ErrNullNorm) {
2763 						silent_cerr(sType << "(" << uLabel << ") has null direction" << std::endl);
2764 						throw ErrNullNorm(MBDYN_EXCEPT_ARGS);
2765 					}
2766 
2767 				} else {
2768 					try {
2769 						Dir = HP.GetUnitVecAbs(rf);
2770 					} catch (ErrNullNorm) {
2771 						silent_cerr(sType << "(" << uLabel << ") has null direction" << std::endl);
2772 						throw ErrNullNorm(MBDYN_EXCEPT_ARGS);
2773 					}
2774 				}
2775 
2776 				Arm = HP.GetPosRel(rf);
2777 
2778 				bLegacy = true;
2779 			}
2780 		}
2781 	}
2782 
2783 	const StructDispNode *pDispNode2 = 0;
2784 	const StructNode *pNode2 = 0;
2785 	Vec3 Arm2(Zero3);
2786 	if (bInternal) {
2787 		/* nodo collegato */
2788 		pDispNode2 = pDM->ReadNode<const StructDispNode, Node::STRUCTURAL>(HP);
2789 		pNode2 = dynamic_cast<const StructNode *>(pDispNode2);
2790 
2791 		if (!bDisp) {
2792 			if (pNode2 == 0) {
2793 				silent_cerr(sType << "(" << uLabel << "): "
2794 					"invalid node type at line " << HP.GetLineData() << std::endl);
2795 				throw ErrGeneric(MBDYN_EXCEPT_ARGS);
2796 			}
2797 
2798 			ReferenceFrame rf2(pNode2);
2799 
2800 			/* distanza dal nodo (vettore di 3 elementi) ( solo se e' una forza) */
2801 			if (HP.IsKeyWord("position")) {
2802 				Arm2 = HP.GetPosRel(rf2, rf, Arm);
2803 				bGotPosition = true;
2804 				DEBUGCOUT("Node 2 arm is supplied" << std::endl);
2805 
2806 			} else if (bLegacy) {
2807 				Arm2 = HP.GetPosRel(rf2, rf, Arm);
2808 			}
2809 		}
2810 	}
2811 
2812 	if (bCouple && bInternal && !bGotPosition) {
2813 		silent_cerr(sType << "(" << uLabel << ") "
2814 			"line " << HP.GetLineData() << ": "
2815 			"warning, the syntax changed; "
2816 			"you may safely ignore this warning if you used "
2817 			"the syntax documented for MBDyn >= 1.3.7"
2818 			<< std::endl);
2819 	}
2820 
2821 	TplDriveCaller<Vec3>* pDC = 0;
2822 	if (bLegacy) {
2823 		pDC = DC2TDC(HP.GetDriveCaller(), Dir);
2824 
2825 	} else {
2826 		if (bFollower) {
2827 			pDC = ReadDCVecRel(pDM, HP, rf);
2828 
2829 		} else {
2830 			pDC = ReadDCVecAbs(pDM, HP, rf);
2831 		}
2832 	}
2833 
2834 	bool bOutRel(false);
2835 	if (bFollower && HP.IsKeyWord("output" "relative")) {
2836 		bOutRel = true;
2837 	}
2838 
2839 	flag fOut = pDM->fReadOutput(HP, Elem::FORCE);
2840 
2841 	if (bOutRel) {
2842 		fOut |= StructuralForce::OUTPUT_REL;
2843 	}
2844 
2845 	/* Alloca la forza */
2846 	if (!bCouple) {
2847 		if (!bFollower) {
2848 			if (!bInternal) {
2849 				if (bDisp) {
2850 					SAFENEWWITHCONSTRUCTOR(pEl,
2851 						AbsoluteDispForce,
2852 						AbsoluteDispForce(uLabel, pDispNode, pDC, fOut));
2853 
2854 				} else {
2855 					SAFENEWWITHCONSTRUCTOR(pEl,
2856 						AbsoluteForce,
2857 						AbsoluteForce(uLabel, pNode, pDC, Arm, fOut));
2858 				}
2859 
2860 			} else {
2861 				if (bDisp) {
2862 					SAFENEWWITHCONSTRUCTOR(pEl,
2863 						AbsoluteInternalDispForce,
2864 						AbsoluteInternalDispForce(uLabel, pDispNode, pDispNode2, pDC, fOut));
2865 
2866 				} else {
2867 					SAFENEWWITHCONSTRUCTOR(pEl,
2868 						AbsoluteInternalForce,
2869 						AbsoluteInternalForce(uLabel, pNode, pNode2, pDC, Arm, Arm2, fOut));
2870 				}
2871 			}
2872 
2873 		} else {
2874 			if (!bInternal) {
2875 				SAFENEWWITHCONSTRUCTOR(pEl,
2876 					FollowerForce,
2877 					FollowerForce(uLabel, pNode, pDC, Arm, fOut));
2878 
2879 			} else {
2880 				SAFENEWWITHCONSTRUCTOR(pEl,
2881 					FollowerInternalForce,
2882 					FollowerInternalForce(uLabel, pNode, pNode2, pDC, Arm, Arm2, fOut));
2883 			}
2884 		}
2885 
2886 	} else {
2887 		if (!bFollower) {
2888 			if (!bInternal) {
2889 				SAFENEWWITHCONSTRUCTOR(pEl,
2890 					AbsoluteCouple,
2891 					AbsoluteCouple(uLabel, pNode, pDC, fOut));
2892 
2893 			} else {
2894 				SAFENEWWITHCONSTRUCTOR(pEl,
2895 					AbsoluteInternalCouple,
2896 					AbsoluteInternalCouple(uLabel, pNode, pNode2, pDC, fOut));
2897 			}
2898 
2899 		} else {
2900 			if (!bInternal) {
2901 				SAFENEWWITHCONSTRUCTOR(pEl,
2902 					FollowerCouple,
2903 					FollowerCouple(uLabel, pNode, pDC, fOut));
2904 
2905 			} else {
2906 				SAFENEWWITHCONSTRUCTOR(pEl,
2907 					FollowerInternalCouple,
2908 					FollowerInternalCouple(uLabel, pNode, pNode2, pDC, fOut));
2909 			}
2910 		}
2911 	}
2912 
2913 	std::ostream& os = pDM->GetLogFile();
2914 
2915 	os << "structural";
2916 	if (bInternal) {
2917 		os << " internal";
2918 	}
2919 	if (bFollower) {
2920 		os << " follower";
2921 	} else {
2922 		os << " absolute";
2923 		if (bDisp) {
2924 			os << " displacement";
2925 		}
2926 	}
2927 	if (bCouple) {
2928 		os << " couple";
2929 	} else {
2930 		os << " force";
2931 	}
2932 	os << ": " << uLabel << ' ' << pDispNode->GetLabel()
2933 		<< ' ' << Arm;
2934 
2935 	if (pDispNode2 != 0) {
2936 		os << ' ' << pDispNode2->GetLabel() << ' ' << Arm2;
2937 	}
2938 
2939 	if (bFollower && (pEl->fToBeOutput() & StructuralForce::OUTPUT_REL)) {
2940 		os << " output_relative";
2941 	}
2942 
2943 	os << std::endl;
2944 
2945 	return pEl;
2946 }
2947 
2948