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 };