1 //#**************************************************************
2 //#
3 //# filename:             AverageConstraint.cpp
4 //#
5 //# author:               Gerstmayr Johannes, Reischl Daniel, Peter Gruber
6 //#
7 //# generated:						17.April 2013
8 //# description:          Avearaging Constraint, which computes a weighted average of positions or higher moment_settings
9 //#
10 //# remarks:
11 //#
12 //# Copyright (c) 2003-2013 Johannes Gerstmayr, Linz Center of Mechatronics GmbH, Austrian
13 //# Center of Competence in Mechatronics GmbH, Institute of Technical Mechanics at the
14 //# Johannes Kepler Universitaet Linz, Austria. All rights reserved.
15 //#
16 //# This file is part of HotInt.
17 //# HotInt is free software: you can redistribute it and/or modify it under the terms of
18 //# the HOTINT license. See folder 'licenses' for more details.
19 //#
20 //# bug reports are welcome!!!
21 //# WWW:		www.hotint.org
22 //# email:	bug_reports@hotint.org or support@hotint.org
23 //#***************************************************************************************
24 
25 
26 
27 
28 
29 
30 // TODO:
31 
32 //
33 // Velocity, max_index = 2, ComputeMomentumP, etc.  --> DR + PG
34 // Damping (?) --> DR
35 
36 
37 //Fragen JG:
38 
39 //virtual void GetdRotdqT(const Vector3D& ploc, Matrix& d) {UO() << "ERROR:called Body3D::GetdRotdqT\n";};
40 ////return the derivative d(Rot*vloc)/dq
41 //virtual void GetdRotvdqT(const Vector3D& vloc, const Vector3D& ploc, Matrix& d) {UO() << "ERROR:called Body3D::GetdRotvdqT\n";};
42 
43 #include "element.h"
44 #include "constraint.h"
45 #include "kinematicpairs.h"
46 #include "specialconstraints.h"
47 #include "geomelements.h"
48 #include "elementdataaccess.h"
49 #include "graphicsconstants.h"
50 #include "rendercontext.h"
51 #include "material.h"
52 #include "finiteelement3d.h"
53 #include "averageconstraint.h"
54 #include "femathhelperfunctions.h"
55 
NE_nodouble() const56 int AverageConstraint::NE_nodouble() const
57 {
58 	return elements_nodouble.Length();
59 }
60 
SetElement_nodouble()61 void AverageConstraint::SetElement_nodouble()
62 {
63 	//$ PG 2013-4-24: fill elements_nodouble with all element numbers except 0 (ground)
64 	elements_nodouble.Flush();
65 	sumWeights1 = 0;
66 	sumWeights2 = 0;
67 
68 	for(int i=1; i<=elements.Length(); i++)
69 	{
70 		if(elements(i))
71 		{
72 			elements_nodouble.AddIfNotExists(elements(i));
73 		}
74 		sumWeights1 += weights1(i);
75 	}
76 	for(int i=1; i<=elements2.Length(); i++)
77 	{
78 		if(elements2(i))
79 		{
80 			elements_nodouble.AddIfNotExists(elements2(i));
81 		}
82 		sumWeights2 += weights2(i);
83 	}
84 }
85 
CheckConsistency(mystr & errorstr)86 int AverageConstraint::CheckConsistency(mystr& errorstr) //rv==0 --> OK, rv==1 --> can not compute, rv==2 --> can not draw and not compute
87 {
88 	int rv = Constraint::CheckConsistency(errorstr);
89 	if (rv) return rv;
90 
91 	if (IS() > MAX_IS)
92 	{
93 		errorstr = mystr("ERROR: AverageConstraint: Maximum allowed implicit size is ")+mystr(MAX_IS)+mystr("!\n");
94 		rv = 1;
95 	}
96 
97 	if(sumWeights1 <= 0)
98 	{
99 		errorstr = mystr("ERROR: AverageConstraint: The sum of the weights of kinematic pair 1 has to be greater than zero!\n");
100 		rv = 1;
101 	}
102 	if(sumWeights2 <= 0)
103 	{
104 		errorstr = mystr("ERROR: AverageConstraint: The sum of the weights of kinematic pair 2 has to be greater than zero!\n");
105 		rv = 1;
106 	}
107 	for(int i=1; i<=moment_settings.Length(); i++)
108 	{
109 		if(GetMomentOrder(i)<0)
110 		{
111 			errorstr = mystr("ERROR: AverageConstraint: The order p of the polynomial ") + mystr(i) + mystr(" has to be an integer with p >= 0 !\n");
112 			rv = 1;
113 		}
114 	}
115 
116 	// can not draw errors ==> rv = 2
117 	if(!(elements.Length() == weights1.Length() && ((elements.Length() == loccoords.Length())||(elements.Length() == nodes.Length()))))
118 	{
119 		errorstr = mystr("ERROR: AverageConstraint: The number of elements of kinematic pair 1 has to be equal to the number of weights and coordinates (or nodes)!\n");
120 		rv = 2;
121 	}
122 	if(!(elements2.Length() == weights2.Length() && ((elements2.Length() == loccoords2.Length())||(elements2.Length() == nodes2.Length()))))
123 	{
124 		errorstr = mystr("ERROR: AverageConstraint: The number of elements of kinematic pair 2 has to be equal to the number of weights and coordinates (or nodes)!\n");
125 		rv = 2;
126 	}
127 	if(GetAverageConstraintType() == ACT_None)
128 	{
129 		errorstr = mystr("ERROR: AverageConstraint: You must not mix formulations with local nodes and local coordinates.\n");
130 		rv = 2;
131 	}
132 
133 	return rv;
134 }
135 
136 // for constraints only, these are the necessary (!) access functions!
GetNecessaryKinematicAccessFunctions(TArray<int> & KinAccFunc,int numberOfKinematicPair)137 void AverageConstraint::GetNecessaryKinematicAccessFunctions(TArray<int> &KinAccFunc, int numberOfKinematicPair)
138 {
139 	KinAccFunc.SetLen(0);
140 	int kaf = (int)(TKinematicsAccessFunctions(TKAF_none));
141 	if (is_nodal_constraint)
142 	{
143 		kaf = (int)(TKinematicsAccessFunctions(kaf+TKAF_node_position+TKAF_D_node_pos_D_q+TKAF_node_ref_conf_position));
144 	}
145 	else
146 	{
147 		kaf = (int)(TKinematicsAccessFunctions(kaf+TKAF_position+TKAF_D_pos_D_q+TKAF_ref_conf_position));
148 		if (UseLocalCoordinateSystem())
149 		{
150 			kaf = (int)(TKinematicsAccessFunctions(kaf+TKAF_D_rot_v_D_q));
151 		}
152 	}
153 
154 	KinAccFunc.Add(kaf);
155 }
156 
ElementDefaultConstructorInitialization()157 void AverageConstraint::ElementDefaultConstructorInitialization()
158 {
159 	SetPenaltyFormulation(0);
160 	SetJointLocalFrame(Matrix3D(1.));
161 	stiffness_in_joint_local_frame = 0;
162 	SetUseLocalCoordinateSystem(0);
163 	is_nodal_constraint = 0;
164 	elements_share_dofs = 0;
165 
166 	velocity_constraint = 0;
167 	elementname = GetElementSpec();
168 
169 	Vector datainit(DataS());
170 	datainit.SetAll(0.);
171 	SetDataInit(datainit);
172 
173 	// dummy values
174 	// nodes, elements and loccoords are always of length 2 because this is the concept of BasePointJoint
175 	nodes.Set2(0,0);
176 	elements.Set2(1,2);
177 
178 	scaling_factor = 1.;
179 }
180 
Initialize()181 void AverageConstraint::Initialize()
182 {
183 	//do not use BasePointJoint::Initialize because then the wrong SetPos2ToGlobalCoord is called
184 	Constraint::Initialize();
185 
186 	if(GetAverageConstraintType() == ACT_Nodes)   // if there exists a '0' in IVector nodes, then this constraint is not a is_nodal_constraint
187 	{
188 		is_nodal_constraint = 1;
189 	}
190 
191 	SetMomentumPolynomial();
192 
193 	// find if there are dofs which are shared by more than one element
194 	if (!ElementsShareDOFs())
195 	{
196 		TArray<int> dofs;
197 		TArray<int> flags_redundant;
198 		for (int i=1; i<=NE_nodouble(); i++)
199 		{
200 			//Element* el_ptr = &GetElem_nodouble(i);
201 			dofs.Append(GetElem_nodouble(i).GetLTGArray());
202 			/*for (int j=1; j<=el_ptr->SS(); j++)
203 			{
204 				dofs.Add(el_ptr->LTG(j));
205 			}*/
206 		}
207 		FindRedundantEntries_QSort(dofs, flags_redundant, 0);
208 		if (flags_redundant.Find(1))
209 		{
210 			SetElementsShareDOFS();
211 		}
212 	}
213 }
214 
215 // returns the type of constraint (coord based or node based) depending on the data in the TArrays
GetAverageConstraintType() const216 AverageConstraintType AverageConstraint::GetAverageConstraintType() const
217 {
218 	TArray<int> all_nodes(nodes); all_nodes.Append(nodes2);
219 
220 	if (all_nodes.Length() > 0)
221 	{
222 		bool has_positive_entries = false;
223 		bool all_entries_are_positive = true;
224 
225 		for (int i=1; i<=all_nodes.Length(); i++)
226 		{
227 			if (all_nodes(i)>0)
228 			{
229 				has_positive_entries = true;
230 			}
231 			if (all_nodes(i)<=0)
232 			{
233 				all_entries_are_positive = false;
234 			}
235 		}
236 
237 		if (has_positive_entries)
238 		{
239 			if (all_entries_are_positive)
240 			{
241 				return ACT_Nodes;
242 			}
243 			else
244 			{
245 				return ACT_None;
246 			}
247 		}
248 	}
249 
250 	if (loccoords.Length() == elements.Length() && loccoords2.Length() == elements2.Length())
251 	{
252 		return ACT_Loccoords;
253 	}
254 
255 	return ACT_None;
256 }
257 
CopyFrom(const Element & e)258 void AverageConstraint::CopyFrom(const Element& e)
259 {
260 	BasePointJoint::CopyFrom(e);
261 	const AverageConstraint& ce = (const AverageConstraint&)e;
262 
263 	nodes2			= ce.nodes2;
264 	loccoords2	= ce.loccoords2;
265 	elements2		= ce.elements2;
266 	weights1		= ce.weights1;
267 	weights2		= ce.weights2;
268 	sumWeights1	= ce.sumWeights1;
269 	sumWeights2	= ce.sumWeights2;
270 	polynomial_1 = ce.polynomial_1;
271 	polynomial_2 = ce.polynomial_2;
272 
273 	moment_settings			= ce.moment_settings;
274 	stiffnesses	= ce.stiffnesses;
275 	elements_nodouble	= ce.elements_nodouble;
276 	is_nodal_constraint = ce.is_nodal_constraint;
277 	elements_share_dofs = ce.elements_share_dofs;
278 
279 	scaling_factor = ce.scaling_factor;
280 }
281 
GetElementData(ElementDataContainer & edc)282 void AverageConstraint::GetElementData(ElementDataContainer& edc) 		//fill in all element data
283 {
284 	BasePointJoint::GetElementData(edc);
285 	ElementData ed;
286 
287 	Matrix m;
288 	m.SetSize(loccoords.Length(),3);
289 	for(int i=1; i<=loccoords.Length();i++)
290 	{
291 		Vector v;
292 		v.Set3D(loccoords(i).X(),loccoords(i).Y(),loccoords(i).Z());
293 		m.SetRowVec(v,i);
294 	}
295 	int cols = 3;
296 	int rows = loccoords.Length();
297 	ed.SetMatrix(m.GetMatPtr(),rows,cols,"positions");
298 	ed.SetToolTipText("(local) positions of the points of kinematic pair 1");
299 	edc.TreeAdd("Position1",ed);
300 
301 	m.SetSize(loccoords2.Length(),3);
302 	for(int i=1; i<=loccoords2.Length();i++)
303 	{
304 		Vector v;
305 		v.Set3D(loccoords2(i).X(),loccoords2(i).Y(),loccoords2(i).Z());
306 		m.SetRowVec(v,i);
307 	}
308 	cols = 3;
309 	rows = loccoords2.Length();
310 	ed.SetMatrix(m.GetMatPtr(),rows,cols,"positions");
311 	ed.SetToolTipText("(local) positions of the points of kinematic pair 2");
312 	edc.TreeAdd("Position2",ed);
313 
314 	m.SetSize(moment_settings.Length(),3);
315 	for(int i=1; i<=moment_settings.Length();i++)
316 	{
317 		Vector v;
318 		v.Set3D(moment_settings(i).Get(1),moment_settings(i).Get(2),moment_settings(i).Get(3));
319 		m.SetRowVec(v,i);
320 	}
321 	cols = 3;
322 	rows = moment_settings.Length();
323 	ed.SetMatrix(m.GetMatPtr(),rows,cols,"moment_settings");
324 	ed.SetToolTipText("moment_settings(i) = [constrained coordinate, moment order, moment coordinate], e.g. rz*pow(y,4) = [3,4,2]; rx*pow(z,2) = [1,2,3]; ry*pow(s,3) = [2,3,0] (with 's': arc length); ry = [2,0,0]");
325 	edc.TreeAdd("Physics",ed);
326 }
327 
SetElementData(ElementDataContainer & edc)328 int AverageConstraint::SetElementData(ElementDataContainer& edc) //set element data according to ElementDataContainer
329 {
330 	int rv = BasePointJoint::SetElementData(edc);
331 
332 	int rows,cols;
333 	double *mp;
334 
335 	if(edc.TreeGetMatrix("Position1.positions",&mp,rows,cols))
336 	{
337 		Matrix m(rows,cols,mp);
338 		loccoords.SetLen(rows);
339 		for(int i=1; i<=rows; i++)
340 		{
341 			loccoords(i) = Vector3D(m(i,1),m(i,2),m(i,3));
342 		}
343 	}
344 
345 	if(edc.TreeGetMatrix("Position2.positions",&mp,rows,cols))
346 	{
347 		Matrix m(rows,cols,mp);
348 		loccoords2.SetLen(rows);
349 		for(int i=1; i<=rows; i++)
350 		{
351 			loccoords2(i) = Vector3D(m(i,1),m(i,2),m(i,3));
352 		}
353 	}
354 
355 	if(edc.TreeGetMatrix("Physics.moment_settings",&mp,rows,cols))
356 	{
357 		Matrix m(rows,cols,mp);
358 		moment_settings.SetLen(rows);
359 		for(int i=1; i<=rows; i++)
360 		{
361 			moment_settings(i) = int3(m(i,1),m(i,2),m(i,3));
362 		}
363 	}
364 
365 	return rv;
366 }
367 
GetAvailableSpecialValues(TArrayDynamic<ReadWriteElementDataVariableType> & available_variables)368 int AverageConstraint::GetAvailableSpecialValues(TArrayDynamic<ReadWriteElementDataVariableType>& available_variables)
369 {
370 	//BasePointJoint::GetAvailableSpecialValues(available_variables);
371 
372 	// Automatic entries for this class
373 
374 	// Manual READ entries for this class
375 
376 	// Manual WRITE entries for this class
377 
378 	return 0;
379 }
380 
ReadSingleElementData(ReadWriteElementDataVariableType & RWdata)381 int AverageConstraint::ReadSingleElementData(ReadWriteElementDataVariableType& RWdata)
382 {
383 	//// call base class routine
384 	////int rv = BasePointJoint::ReadSingleElementData(RWdata);
385 	////if (rv == 1) return 1;
386 
387 	//// manual things to read
388 	//if(RWdata.variable_name.CStrCompare("Internal.actor_force") )
389 	//{
390 	//	RWdata.value = ComputeRopeForce(mbs->GetTime());
391 	//	return 1;
392 	//}
393 	//if(RWdata.variable_name.CStrCompare("Internal.rope_length") )
394 	//{
395 	//	RWdata.value = GetLengthOfRope();
396 	//	return 1;
397 	//}
398 	//if(RWdata.variable_name.CStrCompare("Internal.coiled_length") )
399 	//{
400 	//	RWdata.value = coiled_length;
401 	//	return 1;
402 	//}
403 
404 	//return ReadSingleElementDataAuto(RWdata);
405 	return 1;
406 }
407 
WriteSingleElementData(const ReadWriteElementDataVariableType & RWdata)408 int AverageConstraint::WriteSingleElementData(const ReadWriteElementDataVariableType& RWdata)
409 {
410 	//// call base class routine ( not required in Element )
411 	//int rv = BasePointJoint::WriteSingleElementData(RWdata);
412 	//if (rv == 1) return 1;
413 	////manual things to write
414 	//if(RWdata.variable_name.CStrCompare("Internal.coiled_length"))
415 	//{
416 	//	coiled_length = RWdata.value;
417 	//	return 1;
418 	//}
419 
420 	//return WriteSingleElementDataAuto(RWdata);
421 	return 1;
422 }
423 
SetAverageConstraint_LocalNodes_to_LocalNodes(TArray<int> element_numbers1,TArray<int> node_numbers1,Vector weights1_i,TArray<int> element_numbers2,TArray<int> node_numbers2,Vector weights2_i)424 void AverageConstraint::SetAverageConstraint_LocalNodes_to_LocalNodes(TArray<int> element_numbers1, TArray<int> node_numbers1, Vector weights1_i, TArray<int> element_numbers2, TArray<int> node_numbers2, Vector weights2_i)
425 {
426 
427 }
SetAverageConstraint_LocalCoords_to_LocalCoords(TArray<int> element_numbers1,TArray<Vector3D> loccoords1_i,Vector weights1_i,TArray<int> element_numbers2,TArray<Vector3D> loccoords2_i,Vector weights2_i)428 void AverageConstraint::SetAverageConstraint_LocalCoords_to_LocalCoords(TArray<int> element_numbers1, TArray<Vector3D> loccoords1_i, Vector weights1_i, TArray<int> element_numbers2, TArray<Vector3D> loccoords2_i, Vector weights2_i)
429 {
430 	elements = element_numbers1;
431 	loccoords = loccoords1_i;
432 	weights1 = weights1_i;
433 
434 	elements2 = element_numbers2;
435 	loccoords2 = loccoords2_i;
436 	weights2 = weights2_i;
437 
438 	SetElement_nodouble();
439 }
SetAverageConstraint_LocalNodes_to_GlobalPos(TArray<int> element_numbers1,TArray<int> node_numbers1,Vector weights1_i,TArray<Vector3D> ground,Vector weights2_i)440 void AverageConstraint::SetAverageConstraint_LocalNodes_to_GlobalPos(TArray<int> element_numbers1, TArray<int> node_numbers1, Vector weights1_i, TArray<Vector3D> ground, Vector weights2_i)
441 {
442 	elements = element_numbers1;
443 	nodes = node_numbers1;
444 	weights1 = weights1_i;
445 
446 	elements2.SetLen(weights2_i.Length());
447 	elements2.SetAll(0);
448 	loccoords2 = ground;
449 	weights2 = weights2_i;
450 
451 	SetElement_nodouble();
452 }
SetAverageConstraint_LocalCoords_to_GlobalPos(TArray<int> element_numbers1,TArray<Vector3D> loccoords1,Vector weights1_i,TArray<Vector3D> ground,Vector weights2_i)453 void AverageConstraint::SetAverageConstraint_LocalCoords_to_GlobalPos(TArray<int> element_numbers1, TArray<Vector3D> loccoords1, Vector weights1_i, TArray<Vector3D> ground, Vector weights2_i)
454 {
455 	elements = element_numbers1;
456 	loccoords = loccoords1;
457 	weights1 = weights1_i;
458 
459 	elements2.SetLen(weights2_i.Length());
460 	elements2.SetAll(0);
461 	loccoords2 = ground;
462 	weights2 = weights2_i;
463 
464 	SetElement_nodouble();
465 }
466 
467 //$ PG 2013-4-24: [ just for testing with existing model
SetEdgeConstraint_Displacement(const IVector & element_numbers1,const TArray<Vector3D> & loccoords1,const Vector & weights,const TArray<int3> & moments_i,const Matrix & prescribed_displacements,const Vector & stiffnesses)468 void AverageConstraint::SetEdgeConstraint_Displacement(const IVector& element_numbers1, const TArray<Vector3D>& loccoords1, const Vector& weights, const TArray<int3>& moments_i, const Matrix& prescribed_displacements, const Vector& stiffnesses)
469 {
470 	// is input valid?
471 	int len=element_numbers1.Length();
472 	assert(len > 0);
473 	assert(loccoords1.Length() == len);
474 	assert(prescribed_displacements.Getrows() == 0 || prescribed_displacements.Getrows() == len);
475 
476 	// define ground points based on element_numbers1, loccoords1, constrained_direction, and prescribed_displacements
477 	TArray<Vector3D> ground;
478 	ground.SetLen(len);
479 	for(int i=1; i<=ground.Length(); i++)
480 	{
481 		ground(i) = GetMBS()->GetElement(element_numbers1(i)).GetRefConfPos(loccoords1(i));
482 	}
483 	if (prescribed_displacements.Getrows() == len)
484 	{
485 		for(int i=1; i<=ground.Length(); i++)
486 		{
487 			ground(i) += Vector3D(prescribed_displacements(i,1), prescribed_displacements(i,2), 0.);
488 		}
489 	}
490 
491 	// call set function (same weights for material and ground points)
492 	SetAverageConstraint_LocalCoords_to_GlobalPos(element_numbers1, loccoords1, weights, ground, weights);
493 	SetMoments(moments_i, stiffnesses); //Lagrange (Penalty would require stiffnesses for each of the moment_settings here)
494 }
495 //$ PG 2013-4-24: ]
496 
EvalF2(Vector & f,double t)497 void AverageConstraint::EvalF2(Vector& f, double t)
498 {
499 	// f = [f_el1, f_el2,... f_el1_vel, f_el2_vel]
500 	// eli is the i-th element in the list of elements_no_double
501 
502 	if(!UsePenaltyFormulation())
503 		return;	// no penalty method --> Lagrange multiplier --> no EvalF2
504 
505 	ConstVector<FEmaxDOF> f_el;
506 	int offset = 0;
507 	int sos;
508 
509 	Vector momentum_times_stiffness(stiffnesses);
510 	for(int m=1; m<=moment_settings.Length();m++)
511 	{
512 		momentum_times_stiffness(m)*=ComputeMomentum(t,m);
513 	}
514 
515 	// compute the f-vector f_el for each element
516 	// add f_el to the correct position in the f-vector of the constraint
517 	for (int locel=1; locel <= NE_nodouble(); locel++)
518 	{
519 		sos = GetElem_nodouble(locel).SOS();
520 		f_el.SetLen(sos);
521 		f_el.SetAll(0.);
522 		ComputeMomentumDerivative(t,locel,momentum_times_stiffness,f_el);	// compute f_el
523 
524 		for(int j=1; j<=sos; j++)
525 		{
526 			f(offset+j) -= f_el(j);
527 		}
528 		offset+=sos;
529 	}
530 
531 }
532 
533 // needed for sensor
534 //Vector3D AverageConstraint::ComputeForce(double t, int moment_index) const
535 // returns force per unit length(area/volume/...  depends on definition of weights by user) at specified position and time
ComputeForce(double t,int pos_nr,int kinpair) const536 Vector3D AverageConstraint::ComputeForce(double t, int pos_nr, int kinpair) const
537 {
538 	Vector3D force(0.);
539 
540 	if (UsePenaltyFormulation())
541 	{
542 		for (int moment_idx=1; moment_idx<=moment_settings.Length(); moment_idx++)
543 		{
544 			// f += c*M*f(pos)*v
545 			force += stiffnesses(moment_idx)*ComputeMomentum(t,moment_idx)*GetMomentumPolynomial(kinpair, pos_nr, moment_idx)*GetFrameVector(GetConstrainedDirection(moment_idx));
546 		}
547 	}
548 	else   // Lagrange
549 	{
550 		for (int moment_idx=1; moment_idx<=moment_settings.Length(); moment_idx++)
551 		{
552 			// f += lambda*f(pos)*v
553 			force += (XG(moment_idx)*GetMomentumPolynomial(kinpair, pos_nr, moment_idx))*GetFrameVector(GetConstrainedDirection(moment_idx));
554 		}
555 		force *= 1./scaling_factor;
556 	}
557 
558 	return force;
559 }
560 
561 //Vector3D AverageConstraint::ComputeForce(double t, int kinpair) const
562 //{
563 //	const TArray<int>& elements_kinpair = (kinpair==1) ? elements : elements2 ;
564 //	const Vector& weights = (kinpair==1) ? weights1 : weights2 ;
565 //
566 //	Vector3D force(0.);
567 //	for(int i=1; i<=elements_kinpair.Length(); i++)
568 //	{
569 //		force += ComputeForce(t, kinpair, i)*weights(i);
570 //	}
571 //
572 //	return force;
573 //}
574 
575 // rotation to the correct coordinate system (local frame)
576 // subtraction of the prescribed positions
577 // evaluation of the polynomial momenti
578 // returns "C", see definition of "C" in section "equation" of pdf user-docu
ComputeMomentum(double t,int moment_index) const579 double AverageConstraint::ComputeMomentum(double t, int moment_index) const
580 {
581 	double val = 0;
582 	double component = 0;
583 	Vector3D pos;
584 
585 	Vector3D dv = GetFrameVector(GetConstrainedDirection(moment_index));
586 
587 	for(int i=1; i<=elements.Length(); i++)
588 	{
589 		const Body3D& b = GetBody3D(1,i);
590 		if(is_nodal_constraint)
591 		{
592 			pos = b.GetNodePos(nodes(i));
593 		}
594 		else
595 		{
596 			pos = b.GetPos(loccoords(i));
597 		}
598 
599 		component = pos*dv;
600 
601 		// computation of the momenti of higher orders
602 		component *= GetMomentumPolynomial(1, i, moment_index);
603 		component *= weights1(i);
604 		val += component;
605 	}
606 
607 	for (int i=1; i<=elements2.Length(); i++)
608 	{
609 		if (elements2(i))
610 		{
611 			const Body3D& b = GetBody3D(2,i);
612 			if (is_nodal_constraint)
613 			{
614 				pos = b.GetNodePos(nodes2(i));
615 			}
616 			else
617 			{
618 				pos = b.GetPos(loccoords2(i));
619 			}
620 		}
621 		else	// ground joint --> relative position
622 		{
623 			pos = loccoords2(i);
624 		}
625 
626 		component = pos*dv;
627 
628 		// computation of the momenti of higher orders
629 		component *= GetMomentumPolynomial(2, i, moment_index);
630 		component *= weights2(i);
631 		val -= component;
632 	}
633 	return val;
634 }
635 
ComputeMomentumDerivative(double t,int locelemind,const Vector & multiplier,Vector & f)636 void AverageConstraint::ComputeMomentumDerivative(double t, int locelemind, const Vector& multiplier, Vector& f)
637 {
638 	// this function computes the summation over all moment derivatives \nabla_q M_k(q)
639 	// the parameter "multiplier" is a Vector of lagrange multipliers or stiffness parameters (for penalty - one for each moment -- see member TArray<int2> moment_settings),
640 
641 
642 	// In case the the global directions shall be constrained, only the GetPos()-terms in ComputeMomentum are dependent on element-DOFs, i.e. the derivative
643 	// basically involves the computations of Body3D::GetdPosdqT(..) for each of the elements addressed by the array elements_nodouble.
644 	// Corresponding to these elements the local residual vector f is provided as an input-output argument.
645 
646 	//
647 	// In case the local (and not the global) directions of the body(ies) shall be constrained (UseLocalCoordinateSystem() == 1), then another term  (~ Body3D::GetdRotvdqT, since the rotation depends on q of the first kinpair)
648 	// has to be added corresponding to the derivative of the constrained direction (see GetFrameVector(..)) w.r.t. the element dofs.
649 
650 
651 	int global_element_number = elements_nodouble(locelemind);
652 
653 	ConstMatrix<FEmaxDOF*3> drotvdqT(GetMBS()->GetElementPtr(global_element_number)->SOS(), GetMBS()->GetElementPtr(global_element_number)->Dim(), 1);
654 	ConstMatrix<FEmaxDOF*3> dposdqT(GetMBS()->GetElementPtr(global_element_number)->SOS(), GetMBS()->GetElementPtr(global_element_number)->Dim(), 1);
655 	ConstVector<FEmaxDOF> temp_vector(GetMBS()->GetElementPtr(global_element_number)->SOS(), 1);
656 
657 	for (int k=1; k<=NKinPairs(); k++)   //k= 1 or 2 of kinematic pair
658 	{
659 		TArray<int>& elements_k = (k==1) ? elements : elements2 ;
660 		TArray<Vector3D>& loccoords_k = (k==1) ? loccoords : loccoords2 ;
661 		TArray<int>& nodes_k = (k==1) ? nodes : nodes2 ;
662 		Vector& weights_k = (k==1) ? weights1 : weights2 ;
663 		int sign_k = (k==1) ? 1 : -1 ;
664 
665 		for (int i=1; i<=elements_k.Length(); i++)    //loop over positions
666 		{
667 			if (elements_k.Get(i) == global_element_number)
668 			{
669 				Body3D& b = GetBody3D(k,i);
670 
671 				if (is_nodal_constraint)
672 				{
673 					b.GetNodedPosdqT(nodes_k(i), dposdqT);
674 				}
675 				else
676 				{
677 					b.GetdPosdqT(loccoords_k(i), dposdqT);
678 				}
679 
680 				for (int m=1; m<=moment_settings.Length(); m++)    //loop over (direction, polynomial-order) - couples
681 				{
682 					if (fabs(multiplier(m))>1e-14)   // non-zero (numerically)
683 					{
684 						Mult(dposdqT, GetFrameVector(GetConstrainedDirection(m)), temp_vector);
685 						f += (temp_vector)*(sign_k*GetMomentumPolynomial(k, i, m)*weights_k(i)*multiplier(m));
686 
687 						// if constrained direction d is dependent on element-dofs, then the product rule causes a second term
688 						if (UseLocalCoordinateSystem())
689 						{
690 							Vector3D pos;
691 
692 							// determine constant part e_m of rotation (according to AverageConstraint::GetFrameVector), and apply it to GetdRotvdqT as argument 'vloc'
693 							Vector3D e_m(0.);
694 							e_m(GetConstrainedDirection(m)) = 1.;
695 
696 							if(stiffness_in_joint_local_frame)
697 							{
698 								e_m = e_m*JA0i;
699 							}
700 
701 							if(is_nodal_constraint)
702 							{
703 								GetMBS()->UO(UO_LVL_err) << "ERROR: AverageConstraint::ComputeMomentumDerivative not yet implemented for case (UseLocalCoordinateSystem() && is_nodal_constraint)!\n";
704 							}
705 							else
706 							{
707 								b.GetdRotvdqT(e_m, loccoords_k(i), drotvdqT);
708 								pos = b.GetPos(loccoords_k(i));
709 							}
710 
711 							Mult(drotvdqT, pos, temp_vector);
712 							f += (temp_vector)*(sign_k*GetMomentumPolynomial(k, i, m)*weights_k(i)*multiplier(m));
713 						}
714 					}
715 				}
716 			}
717 		}
718 	}
719 }
720 
721 // get x^p (lever_direction=1), y^p (lever_direction=2), z^p (lever_direction=3), or \xi^p (lever_direction=0)
GetMomentumPolynomial(const int kinpair,const int pos_nr,const int moment_index) const722 double AverageConstraint::GetMomentumPolynomial(const int kinpair, const int pos_nr, const int moment_index) const
723 {
724 	const Matrix& polynomial = (kinpair==1) ? polynomial_1 : polynomial_2;
725 	return polynomial(moment_index, pos_nr);
726 }
727 
728 // computation of x^p (lever_direction=1), y^p (lever_direction=2), z^p (lever_direction=3), or \xi^p (lever_direction=0)
729 // PG will improve this matrices, such that the numerical solver is happy (orthogonalize moments --> integral of higher moments = 0)
SetMomentumPolynomial()730 void AverageConstraint::SetMomentumPolynomial()
731 {
732 	for (int kinpair=1; kinpair <= 2; kinpair++)
733 	{
734 		Matrix& polynomial = (kinpair==1) ? polynomial_1 : polynomial_2;
735 		Vector& weights = (kinpair==1) ? weights1 : weights2;
736 		polynomial.SetSize(moment_settings.Length(), NElements(kinpair));
737 
738 		// precomputation of center and deviation of pointcloud (\max_{i,j} |(p_i-p_j) . d| where d is e1, e2, and e3 of frame (see GetFrameVector(i))
739 		Vector3D pos = GetRefConfPos(kinpair, 1);
740 		Vector3D pointcloud_center(pos);
741 		Vector3D pointcloud_size_max;
742 		for (int i=1; i<=3; i++)
743 		{
744 			pointcloud_size_max(i) = pos*GetFrameVector(i);
745 		}
746 		Vector3D pointcloud_size_min(pointcloud_size_max);
747 		for (int pos_nr=2; pos_nr <= NElements(kinpair); pos_nr++)
748 		{
749 			pos = GetRefConfPos(kinpair, pos_nr);
750 			pointcloud_center += pos;
751 			for (int i=1; i<=3; i++)
752 			{
753 				pointcloud_size_max(i) = max(pointcloud_size_max(i), pos*GetFrameVector(i));
754 				pointcloud_size_min(i) = min(pointcloud_size_min(i), pos*GetFrameVector(i));
755 			}
756 		}
757 		pointcloud_center *= 1./NElements(kinpair);  // arithmetic midpoint
758 		Vector3D pointcloud_size = pointcloud_size_max - pointcloud_size_min;
759 
760 		// computation of polynomial values
761 		for (int pos_nr=1; pos_nr <= NElements(kinpair); pos_nr++)
762 		{
763 			for (int moment_index=1; moment_index <= moment_settings.Length(); moment_index++)
764 			{
765 				int moment_order = GetMomentOrder(moment_index);
766 				int lever_direction = GetLeverDirection(moment_index);
767 				if (moment_order == 0)
768 				{
769 					polynomial(moment_index, pos_nr) = 1.;
770 				}
771 				else
772 				{
773 					double xi;   // position in lever direction (if lever_direction != 0) or arc length along curve (if lever_direction == 0)
774 					if (lever_direction == 0)   // assuming trapecoid rule for back-calculation of xi from weights1/2
775 					{
776 						// first compute xi out of the information of weights and pos_nr
777 						// additional information: xi e [-1,1]
778 
779 						if (pos_nr == 1)
780 						{
781 							xi = -1;
782 						}
783 						else if (pos_nr == weights.Length())
784 						{
785 							xi = 1;
786 						}
787 						else
788 						{
789 							xi = weights.Sum(pos_nr)-weights(pos_nr)/2;	// at this moment: xi e [0,sumWeights1]
790 							xi = 2*xi/sumWeights1 - 1;	// xi e ]-1,1[
791 						}
792 					}
793 					else // lever direction is set to 1, 2, or 3
794 					{
795 						if (pointcloud_size(lever_direction))
796 						{
797 						Vector3D pos = GetRefConfPos(kinpair, pos_nr);
798 						xi = ((pos - pointcloud_center) * GetFrameVector(lever_direction)) * 2. / pointcloud_size(lever_direction);
799 						}
800 						else
801 						{
802 							GetMBS()->UO(UO_LVL_err) << "ERROR: either just one point specified, or point cloud is plane in lever direction " << lever_direction << "!\n";
803 							assert(0);
804 						}
805 					}
806 
807 					// then compute the polynomial
808 					polynomial(moment_index, pos_nr) = pow(xi, moment_order);
809 				}
810 			}
811 		}
812 
813 		GetMBS()->UO(UO_LVL_dbg1) << "kinpair = " << kinpair << ", polynomial = " << polynomial << "\n";
814 	}
815 }
816 
GetRefConfPos(int kinpair,int pos_nr) const817 Vector3D AverageConstraint::GetRefConfPos(int kinpair, int pos_nr) const
818 {
819 	// return position of a material point (pos_nr) of body 1/2 (kinpair) in reference configuration
820 	const IVector& element_array = (kinpair == 1) ? elements : elements2;
821 	const TArray<Vector3D>& loccoords_array = (kinpair == 1) ? loccoords : loccoords2;
822 	if (element_array(pos_nr) == 0)  // ground
823 	{
824 		return loccoords_array(pos_nr);
825 	}
826 
827 	return GetBody3D(kinpair, pos_nr).GetRefConfPos(loccoords_array(pos_nr));
828 }
829 
GetFrameVector(int i) const830 Vector3D AverageConstraint::GetFrameVector(int i) const
831 {
832 	Matrix3D A = GetRotMati();
833 	return Vector3D(A(1,i),A(2,i),A(3,i));
834 }
835 
AddElementCqTLambda(double t,int locelemind,Vector & f)836 void AverageConstraint::AddElementCqTLambda(double t, int locelemind, Vector&f)
837 {
838 // we calculate \sum_m lambda_m (\nabla M_m(q)) with respect to element-DOFs:
839 	ConstVector<MAX_IS> lambda(IS(),1);
840 	for (int m=1; m<=IS(); m++)
841 	{
842 		lambda(m) = XG(m);
843 	}
844 
845 	ComputeMomentumDerivative(t, locelemind, lambda, f);
846 	f *= scaling_factor;
847 	//mbs->UO() << "locelem " << locelemind << ": " << f << "\n";
848 	//$ PG 2013-4-26: suggest to rename ComputeMomentumDerivative --> ComputeSumOfMomentumDerivative
849 }
850 
851 
EvalG(Vector & f,double t)852 void AverageConstraint::EvalG(Vector &f, double t)
853 {
854 	if(UsePenaltyFormulation()) return;  // penalty method --> no Lagrange multiplier --> no EvalG
855 
856 	if (MaxIndex() == 3)
857 	{
858 		for(int m=1; m <= moment_settings.Length(); m++)
859 		{
860 			f(m) = ComputeMomentum(t, m);
861 		}
862 	}
863 	else
864 	{
865 		GetMBS()->UO(UO_LVL_err) << "ERROR: in AverageConstraint: MaxIndex() != 3 not implemented yet!\n";
866 	}
867 	f *= scaling_factor;
868 }
869 
870 // old
871 //void AverageConstraint::LinkToElementsPenalty()
872 //{
873 //	LTGreset();
874 //
875 //	int nElems;
876 //	int sos;
877 //	// add all SOS dofs from the elements
878 //	//Position(first SOS)
879 //
880 //	for (int k=1; k <= NKinPairs(); k++)
881 //	{
882 //		if(k==1) nElems = elements.Length();
883 //		else nElems = elements2.Length();
884 //
885 //		for(int i=1; i<=nElems; i++)
886 //		{
887 //			sos = GetElement(k,i).SOS();
888 //			for (int j=1; j <= sos; j++)
889 //			{
890 //				AddLTG(GetElement(k,i).LTG(j));
891 //			}
892 //		}
893 //	}
894 //
895 //	//and Velocity (second SOS):
896 //	for (int k=1; k <= NKinPairs(); k++)
897 //	{
898 //		if(k==1) nElems = elements.Length();
899 //		else nElems = elements2.Length();
900 //
901 //		for(int i=1; i<=nElems; i++)
902 //		{
903 //			sos = GetElement(k,i).SOS();
904 //			for (int j=1; j <= sos; j++)
905 //			{
906 //				AddLTG(GetElement(k,i).LTG(j+sos));
907 //			}
908 //		}
909 //	}
910 //};
911 
912 
LinkToElementsPenalty()913 void AverageConstraint::LinkToElementsPenalty()
914 // f = [f_el1, f_el2,... f_el1_vel, f_el2_vel]
915 // eli is the i-th element in the list of elements_no_double
916 {
917 	LTGreset();
918 	int sos;
919 
920 	// add all SOS dofs from the elements
921 	//Position(first SOS)
922 	for(int i=1; i<=NE_nodouble(); i++)
923 	{
924 		sos = GetElem_nodouble(i).SOS();
925 		for (int j=1; j <= sos; j++)
926 		{
927 			AddLTG(GetElem_nodouble(i).LTG(j));
928 		}
929 	}
930 
931 	//and Velocity (second SOS):
932 	for(int i=1; i<=NE_nodouble(); i++)
933 	{
934 		sos = GetElem_nodouble(i).SOS();
935 		for (int j=1; j <= sos; j++)
936 		{
937 			AddLTG(GetElem_nodouble(i).LTG(j+sos));
938 		}
939 	}
940 };
941 
LinkToElementsLagrange()942 void AverageConstraint::LinkToElementsLagrange()
943 {
944 	if (IsLocalNodeConstraint())
945 	{
946 		//$ PG 2013-4-24: [
947 		for (int i = 1; i <= NE_nodouble(); i++)
948 		{
949 			GetElem_nodouble(i).AddConstraint(this, i);
950 		}
951 		// particularly needed for evaluation of AverageConstraint::AddElementCqTLambda(..., int locelemindex, ...)
952 		// which is called in Element::EvalF2 via
953 		// for (int i=1; i <= constraints.Length(); i++)
954 		// {
955 		//   constraints(i)->AddElementCqTLambda(t, constraintindices(i),f);
956 		// }
957 		// where TArray<Constraint*> constraints and TArray<int> constraintindices are both assembled through calling
958 		// Element::AddConstraint(Constraint* c, int index), which we do right here!
959 		//$ PG 2013-4-24: ]
960 	}
961 }
962 
DrawElement()963 void AverageConstraint::DrawElement()
964 {
965 	Constraint::DrawElement();
966 
967 	Vector3D pos;
968 	int res = 8;
969 	mbs->SetColor(Vector3D(0.,0.,0.8));
970 	for(int i=1; i<=elements.Length(); i++)
971 	{
972 
973 		if(is_nodal_constraint){ pos = mbs->GetElementPtr(elements(i))->GetNodePosD(nodes(i)); }
974 		else								{ pos = mbs->GetElementPtr(elements(i))->GetPosD(loccoords(i)); }
975 		mbs->DrawSphere(pos,GetDrawSizeScalar(),res);
976 	}
977 
978 	mbs->SetColor(Vector3D(0.8,0.1,0.1));
979 	res = 7;
980 	for(int i=1; i<=elements2.Length(); i++)
981 	{
982 		if(elements2(i))
983 		{
984 			if(is_nodal_constraint){ pos = mbs->GetElementPtr(elements2(i))->GetNodePosD(nodes2(i)); }
985 			else								{ pos = mbs->GetElementPtr(elements2(i))->GetPosD(loccoords2(i)); }
986 		}
987 		else
988 		{
989 			pos = loccoords2(i);	// ground
990 		}
991 		mbs->DrawSphere(pos,GetDrawSizeScalar(),res);
992 	}
993 
994 	if(draw_local_frame_size > 0 || draw_local_frame_size == -1)
995 	{
996 		double s = draw_local_frame_size;
997 		if(s == -1) {s = GetMBS()->GetDOption(104); }	// use default value
998 
999 		GetMBS()->ChooseColor(0.3f,0.3f,0.3f);
1000 
1001 		// size of the frame
1002 		Vector3D v1(-0.2*s, 0,0);
1003 		Vector3D v2( s, 0,0);
1004 		Vector3D v3( 0,-0.2*s,0);
1005 		Vector3D v4( 0, s,0);
1006 		Vector3D v5( 0,0,-0.2*s);
1007 		Vector3D v6( 0,0, s);
1008 
1009 		Matrix3D A = GetRotMatiD();
1010 		Vector3D p;
1011 		if(is_nodal_constraint){ p = mbs->GetElementPtr(elements(1))->GetNodePosD(nodes(1)); }
1012 		else								{ p = mbs->GetElementPtr(elements(1))->GetPosD(loccoords(1)); }
1013 
1014 		v1 = p + A*v1;
1015 		v2 = p + A*v2;
1016 		v3 = p + A*v3;
1017 		v4 = p + A*v4;
1018 		v5 = p + A*v5;
1019 		v6 = p + A*v6;
1020 
1021 		double d = GetMBS()->GetDOption(114);
1022 		GetMBS()->MyDrawLine(v1,v2,d);
1023 		GetMBS()->MyDrawLine(v3,v4,d);
1024 		GetMBS()->MyDrawLine(v5,v6,d);
1025 
1026 		char str[20];
1027 		sprintf(str, "X%d", GetOwnNum());
1028 		GetMBS()->GetRC()->PrintText3D((float)v2.X(), (float)v2.Y(), (float)v2.Z(), str);
1029 		sprintf(str, "Y%d", GetOwnNum());
1030 		GetMBS()->GetRC()->PrintText3D((float)v4.X(), (float)v4.Y(), (float)v4.Z(), str);
1031 		sprintf(str, "Z%d", GetOwnNum());
1032 		GetMBS()->GetRC()->PrintText3D((float)v6.X(), (float)v6.Y(), (float)v6.Z(), str);
1033 	}
1034 };