MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
module-cyclocopter.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/modules/module-cyclocopter/module-cyclocopter.cc,v 1.5 2016/02/17 15:41:37 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2009
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  * Author: Mattia Mattaboni <mattia.mattaboni@mail.polimi.it>
33  *
34  * Reworked as runtime loadable module by
35  * Pierangelo Masarati <pierangelo.masarati@polimi.it>
36  */
37 
38 /* Elementi di rotore */
39 
40 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
41 
42 #include <limits>
43 #include <cmath>
44 
45 #include "dataman.h"
46 #include "userelem.h"
47 #include "indvel.h"
48 
49 /* CyclocopterInflow - begin */
50 
51 /* Classe base per i modelli di influsso del ciclocottero:
52  * tutti gli altri modelli sono ottenuti ereditando questa
53  * classe
54 */
55 
57 : virtual public Elem, public UserDefinedElem, public InducedVelocity {
58 protected:
60 
62  // == true: usa la media delle forze sul giro
63  // per calcolare la velocità indotta per il giro successivo
64  // == false: usa il valore istantaneo (eventualmente filtrato)
65 
66 
67  doublereal dRadius; // Rotor radius
68  doublereal dSpan; // Blade length
69  doublereal dArea; // Cylinder longitudinal area
70 
71  doublereal dKappa; // Hover correction coefficient
72 
75 
77  /* dati che servono per il calcolo dell'output */
80 
81  // Coefficienti del filtro di butterworth del second'ordine
83 
84  // Coefficienti del filtro di butterworth del second'ordine
85  void SetFilterCoefficients(doublereal dOmegaFilter, doublereal dDeltaT);
86 
87 public:
88  CyclocopterInflow(unsigned int uL, const DofOwner* pDO);
89  virtual ~CyclocopterInflow(void);
90 
91  virtual Elem::Type GetElemType(void) const;
93 
94  // Elaborazione stato interno dopo la convergenza
95  virtual void
96  AfterConvergence(const VectorHandler& X, const VectorHandler& XP);
97 
98  // output; si assume che ogni tipo di elemento sappia,
99  // attraverso l'OutputHandler, dove scrivere il proprio output
100  virtual void Output(OutputHandler& OH) const;
101 
102  // Contributo al file di Restart
103  virtual std::ostream& Restart(std::ostream& out) const;
104 
105  virtual void SetValue(DataManager *pDM,
108 
109  // Relativo ai ...WithDofs
110  virtual void SetInitialValue(VectorHandler& X);
111 
112  // *******PER IL SOLUTORE PARALLELO********
113  // Fornisce il tipo e la label dei nodi che sono connessi all'elemento
114  // utile per l'assemblaggio della matrice di connessione fra i dofs
115  virtual void
116  GetConnectedNodes(std::vector<const Node *>& connectedNodes) const;
117  // ************************************************
118 
119  virtual unsigned int iGetInitialNumDof(void) const;
120  virtual void
121  InitialWorkSpaceDim(integer* piNumRows, integer* piNumCols) const;
124  const VectorHandler& XCurr);
126  InitialAssRes(SubVectorHandler& WorkVec, const VectorHandler& XCurr);
127 };
128 
129 CyclocopterInflow::CyclocopterInflow(unsigned int uL, const DofOwner* pDO)
130 : Elem(uL, flag(0)),
131 UserDefinedElem(uL, pDO),
132 InducedVelocity(uL, 0, 0, flag(0)),
133 pRotor(0),
134 bFlagAverage(false),
135 dRadius(0.),
136 dSpan(0.),
137 dArea(0.),
138 Weight(0),
139 dWeight(0.),
140 RRot(::Eye3),
141 RRotorTranspose(::Eye3),
142 dUindMean(0.),
143 a1(0.), a2(0.), b0(1.), b1(0.), b2(0.)
144 {
145  NO_OP;
146 }
147 
149 {
150  NO_OP;
151 }
152 
155 {
156  return Elem::LOADABLE;
157 }
158 
161 {
163 }
164 
165 void
167 {
168  NO_OP;
169 }
170 
171 void
173 {
174  if (bToBeOutput()) {
175  OH.Loadable()
176  << std::setw(8) << GetLabel() /* 1 */
177  << " " << RRotorTranspose*Res.Force() /* 2-4 */
178  << " " << RRotorTranspose*Res.Moment() /* 5-7 */
179  << " " << dUindMean /* 8 */
180  << " " << "0." /* 9 */
181  << " " << "0." /* 10 */
182  << " " << "0." /* 11 */
183  << " " << "0." /* 12 */
184  << " " << "0." /* 13 */
185  << " " << "0." /* 14 */
186  << " " << "0." /* 15 */
187  << " " << "0." /* 16 */
188  << std::endl;
189 
190  /* FIXME: check for parallel stuff ... */
191  for (int i = 0; ppRes && ppRes[i]; i++) {
192  OH.Loadable()
193  << std::setw(8) << GetLabel()
194  << ":" << ppRes[i]->GetLabel()
195  << " " << ppRes[i]->pRes->Force()
196  << " " << ppRes[i]->pRes->Moment()
197  << std::endl;
198  }
199  }
200 }
201 
202 std::ostream&
203 CyclocopterInflow::Restart(std::ostream& out) const
204 {
205  return out << "# cyclocopter: not implemented yet" << std::endl;
206 }
207 
208 void
212 {
213  NO_OP;
214 }
215 
216 void
218 {
219  NO_OP;
220 }
221 
222 void
223 CyclocopterInflow::GetConnectedNodes(std::vector<const Node *>& connectedNodes) const
224 {
225  connectedNodes.resize(2);
226  connectedNodes[0] = pCraft;
227  connectedNodes[1] = pRotor;
228 }
229 
230 unsigned int
232 {
233  return 0;
234 }
235 
236 void
238  integer* piNumRows,
239  integer* piNumCols) const
240 {
241  *piNumRows = 0;
242  *piNumCols = 0;
243 }
244 
247  VariableSubMatrixHandler& WorkMat,
248  const VectorHandler& XCurr)
249 {
250  // should not be called, since initial workspace is empty
251  ASSERT(0);
252 
253  WorkMat.SetNullMatrix();
254 
255  return WorkMat;
256 }
257 
260  SubVectorHandler& WorkVec,
261  const VectorHandler& XCurr)
262 {
263  // should not be called, since initial workspace is empty
264  ASSERT(0);
265 
266  WorkVec.ResizeReset(0);
267 
268  return WorkVec;
269 }
270 
271 void
273  doublereal dDeltaT)
274 {
275  /* Butterworth discrete low-pass filter coefficients */
276  if (dDeltaT > 0. && dOmegaFilter > 0.) {
277  doublereal dTmp = 4. + 2.*sqrt(2.)*dOmegaFilter*dDeltaT + dDeltaT*dDeltaT*dOmegaFilter*dOmegaFilter;
278  a1 = (-8. + 2.*dDeltaT*dDeltaT*dOmegaFilter*dOmegaFilter)/dTmp;
279  a2 = (4. - 2.*sqrt(2.)*dOmegaFilter*dDeltaT + dDeltaT*dDeltaT*dOmegaFilter*dOmegaFilter)/dTmp;
280 
281  dTmp = dOmegaFilter*dOmegaFilter*dDeltaT*dDeltaT/dTmp;
282  b0 = dTmp;
283  b1 = 2.*dTmp;
284  b2 = dTmp;
285  }
286 }
287 
288 static bool
290  MBDynParser& HP,
291  unsigned int uLabel,
292  const StructNode *& pCraft,
293  Mat3x3& rrot,
294  const StructNode *& pRotor)
295 {
296  /* aircraft node */
297  pCraft = pDM->ReadNode<const StructNode, Node::STRUCTURAL>(HP);
298 
299  /* rotor orientation with respect to aircraft */
300  rrot = ::Eye3;
301  if (HP.IsKeyWord("orientation")) {
302  ReferenceFrame RF(pCraft);
303  rrot = HP.GetRotRel(RF);
304 
305  } else if (HP.IsKeyWord("hinge")) {
306  silent_cerr("InducedVelocity(" << uLabel << "): deprecated keyword \"hinge\"; use \"orientation\" instead at line " << HP.GetLineData() << std::endl);
307 
308  ReferenceFrame RF(pCraft);
309  rrot = HP.GetRotRel(RF);
310  }
311 
312  /* rotor node */
313  pRotor = pDM->ReadNode<const StructNode, Node::STRUCTURAL>(HP);
314 
315  return true;
316 }
317 
318 static bool
320  MBDynParser& HP,
321  unsigned int uLabel,
322  bool& bFlagAve,
323  doublereal& dR,
324  doublereal& dL,
325  DriveCaller *& pdW,
326  doublereal& dOmegaFilter,
327  doublereal& dKappa,
328  doublereal& dDeltaT)
329 {
330  bFlagAve = HP.GetYesNoOrBool();
331 
332  dR = HP.GetReal();
333  if (dR <= 0.) {
334  silent_cerr("ReadUniform(" << uLabel << "): "
335  "illegal null or negative radius"
336  "for rotor" << uLabel << " at line " << HP.GetLineData()
337  << std::endl);
338  return false;
339  }
340 
341  dL = HP.GetReal();
342  if (dL <= 0.) {
343  silent_cerr("ReadUniform(" << uLabel << "): "
344  "illegal null or negative blade"
345  "length for rotor" << uLabel
346  << " at line " << HP.GetLineData()
347  << std::endl);
348  return false;
349  }
350 
351  pdW = 0;
352  if (HP.IsKeyWord("delay")) {
353  pdW = HP.GetDriveCaller();
354 
355  } else {
356  SAFENEW(pdW, NullDriveCaller);
357  }
358 
359  dOmegaFilter = 0.;
360  if (HP.IsKeyWord("omegacut")) {
361  dOmegaFilter = HP.GetReal();
362  if (dOmegaFilter <= 0) {
363  silent_cerr("Illegal null or negative filter"
364  "cut frequency for rotor" << uLabel
365  << " at line " << HP.GetLineData()
366  << std::endl);
367  return false;
368  }
369  } else {
370  dOmegaFilter = 0.;
371  }
372 
373  dKappa = 1.;
374  if (HP.IsKeyWord("kappa")) {
375  dKappa = HP.GetReal();
376  if (dKappa <= 0) {
377  silent_cerr("Illegal null or negative hover"
378  "correction coefficient" << uLabel
379  << " at line " << HP.GetLineData()
380  << std::endl);
381  return false;
382  }
383  }
384 
385  dDeltaT = 0.;
386  if (HP.IsKeyWord("timestep")) {
387  dDeltaT = HP.GetReal();
388  if (dDeltaT <= 0) {
389  silent_cerr("Illegal null or negative time"
390  "step for rotor" << uLabel
391  << " at line " << HP.GetLineData()
392  << std::endl);
393  return false;
394  }
395 
396  } else {
397  dDeltaT = 0.;
398  }
399 
400  return true;
401 }
402 
403 /* CyclocopterInflow - end */
404 
405 
406 /* CyclocopterNoInflow - begin */
407 
409 : virtual public Elem, public CyclocopterInflow {
410 public:
411  CyclocopterNoInflow(unsigned int uL, const DofOwner* pDO,
412  DataManager* pDM, MBDynParser& HP);
413  virtual ~CyclocopterNoInflow(void);
414 
415  // assemblaggio residuo
416  virtual SubVectorHandler&
417  AssRes(SubVectorHandler& WorkVec,
418  doublereal dCoef,
419  const VectorHandler& XCurr,
420  const VectorHandler& XPrimeCurr);
421 
422  // Somma alla trazione il contributo di un elemento
423  virtual void
424  AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X);
425 
426  // Restituisce ad un elemento la velocita' indotta
427  // in base alla posizione azimuthale
428  virtual Vec3 GetInducedVelocity(Elem::Type type,
429  unsigned uLabel, unsigned uPnt, const Vec3& X) const;
430 
431  // Restituisce ad un elemento la velocità indotta
432  // in base alla posizione azimuthale (usata per
433  // iterare tra calcolo della valocità indotta e
434  // calcolo delle forze aerodinamiche - solo
435  // per il modello di influsso KARI per il ciclocottero)
436 #if 0
437  virtual void GetInducedVelocityIter(const Vec3& X, const Vec3& T, doublereal *UindM, doublereal dTn0, doublereal dTn_dUindM) {
438  NO_OP;
439  };
440 #endif
441 
442  // Restituisce la velocità indotta dalla metà superiore del rotore
443  // ( solo per KARI ciclocottero)
444  virtual doublereal GetW(const Vec3& X) const {
445  return 0.;
446  }
447  virtual doublereal GetPsi(const Vec3& X) const {
448  return 0.;
449  }
450  virtual Mat3x3 GetRRotor(const Vec3& X) const {
452  }
453 
454 };
455 
457  DataManager* pDM, MBDynParser& HP)
458 : Elem(uL, flag(0)),
459 CyclocopterInflow(uL, pDO)
460 {
461  if (HP.IsKeyWord("help")) {
462  silent_cout(
463 " \n"
464 "Module: Cyclocopter \n"
465 "Author: Pierangelo Masarati <pierangelo.masarati@polimi.it> \n"
466 "based on work by \n"
467 " Mattia Mattaboni <mattia.mattaboni@mail.polimi.it> \n"
468 "Organization: Dipartimento di Scienze e Tecnologie Aerospaziali \n"
469 " Politecnico di Milano \n"
470 " http://www.aero.polimi.it/ \n"
471 " Description: This module implements induced velocity models \n"
472 " for cycloidal rotors. \n"
473 " \n"
474 " All rights reserved. \n"
475 "\n"
476 " Usage:\n"
477 " user element: <label> , cycloidal no inflow ,\n"
478 " <aircraft_node_label> ,\n"
479 " [ orientation , (OrientationMatrix) <orientation> , ]\n"
480 " <rotor_node_label>\n"
481 " [ , <output_data> ]\n"
482 " ;\n"
483  << std::endl);
484 
485  if (!HP.IsArg()) {
486  /*
487  * Exit quietly if nothing else is provided
488  */
489  throw NoErr(MBDYN_EXCEPT_ARGS);
490  }
491  }
492 
493  if (!ReadRotorData(pDM, HP, uLabel, pCraft, RRot, pRotor)) {
495  }
496 
497  ppRes = ReadResSets(pDM, HP);
498 
500 }
501 
503 {
504  NO_OP;
505 }
506 
509  doublereal dCoef,
510  const VectorHandler& XCurr,
511  const VectorHandler& XPrimeCurr)
512 {
513  if (bToBeOutput()) {
516  }
517 
518  ResetForce();
519  WorkVec.Resize(0);
520 
521  return WorkVec;
522 }
523 
524 void
525 CyclocopterNoInflow::AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X)
526 {
527  /* Sole se deve fare l'output calcola anche il momento */
528  if (bToBeOutput()) {
529  Res.AddForces(F, M, X);
530  InducedVelocity::AddForce(pEl, pNode, F, M, X);
531  }
532 }
533 
534 Vec3
536  unsigned uLabel, unsigned uPnt, const Vec3& X) const
537 {
538 
539  return Zero3;
540 }
541 
542 /* CyclocopterNoInflow - end */
543 
544 /* CyclocopterUniform1D - begin */
545 
546 /*
547 
548 From Moble: the induced velocity is opposite to the
549 the force generated by the rotor in the direction 3
550 of the rotor reference (the direction 1 of this
551 reference must be align with the rotation axis of
552 the rotor). It should make sense just for a multiblade
553 rotor (not for the one-blade rotor) when the generated
554 force is mainly in one direction.
555 
556 */
557 
559 : virtual public Elem, public CyclocopterInflow {
560 protected:
563 
565 
567 
569 
572 
573  unsigned int iStepCounter;
574 
575  /* dati per il filtraggio delle forze */
577 
578 public:
579  CyclocopterUniform1D(unsigned int uL, const DofOwner* pDO,
580  DataManager* pDM, MBDynParser& HP);
581  virtual ~CyclocopterUniform1D(void);
582 
583  // Elaborazione stato interno dopo la convergenza
584  virtual void
585  AfterConvergence(const VectorHandler& X, const VectorHandler& XP);
586 
587  // output; si assume che ogni tipo di elemento sappia,
588  // attraverso l'OutputHandler, dove scrivere il proprio output
589  virtual void Output(OutputHandler& OH) const;
590 
591  // assemblaggio residuo
592  virtual SubVectorHandler&
593  AssRes(SubVectorHandler& WorkVec,
594  doublereal dCoef,
595  const VectorHandler& XCurr,
596  const VectorHandler& XPrimeCurr);
597 
598  // Somma alla trazione il contributo di un elemento
599  virtual void
600  AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X);
601 
602  // Restituisce ad un elemento la velocita' indotta
603  // in base alla posizione azimuthale
604  virtual Vec3 GetInducedVelocity(Elem::Type type,
605  unsigned uLabel, unsigned uPnt, const Vec3& X) const;
606 
607  // Restituisce ad un elemento la velocità indotta
608  // in base alla posizione azimuthale (usata per
609  // iterare tra calcolo della valocità indotta e
610  // calcolo delle forze aerodinamiche - solo
611  // per il modello di influsso KARI per il ciclocottero)
612 #if 0
613  virtual void GetInducedVelocityIter(const Vec3& X, const Vec3& T, doublereal *UindM, doublereal dTn0, doublereal dTn_dUindM) {
614  NO_OP;
615  };
616 #endif
617 
618  // Restituisce la velocità indotta dalla metà superiore del rotore
619  // ( solo per KARI ciclocottero)
620  virtual doublereal GetW(const Vec3& X) const {
621  return 0.;
622  };
623 
624  virtual doublereal GetPsi(const Vec3& X) const {
625  return 0.;
626  };
627 
628  virtual Mat3x3 GetRRotor(const Vec3& X) const {
630  };
631 };
632 
634  DataManager* pDM, MBDynParser& HP)
635 : Elem(uL, flag(0)),
636 CyclocopterInflow(uL, pDO),
637 RRot3(::Zero3),
638 RRotor(::Eye3),
639 dUindMeanPrev(0.),
640 bFlagIsFirstBlade(true),
641 dAzimuth(0.), dAzimuthPrev(0.),
642 dTz(0.), dTzMean(0.),
643 F(::Zero3), FMean(::Zero3), FMeanOut(::Zero3),
644 iStepCounter(0),
645 Uk(0.), Uk_1(0.), Uk_2(0.), Yk(0.), Yk_1(0.), Yk_2(0.)
646 {
647  if (HP.IsKeyWord("help")) {
648  silent_cout(
649 " \n"
650 "Module: Cyclocopter \n"
651 "Author: Pierangelo Masarati <pierangelo.masarati@polimi.it> \n"
652 "based on work by \n"
653 " Mattia Mattaboni <mattia.mattaboni@mail.polimi.it> \n"
654 "Organization: Dipartimento di Scienze e Tecnologie Aerospaziali \n"
655 " Politecnico di Milano \n"
656 " http://www.aero.polimi.it/ \n"
657 " Description: This module implements induced velocity models \n"
658 " for cycloidal rotors. \n"
659 " \n"
660 " All rights reserved. \n"
661 "\n"
662 " Usage:\n"
663 " user element: <label> , cycloidal uniform 1D ,\n"
664 " <aircraft_node_label> ,\n"
665 " [ orientation , (OrientationMatrix) <orientation> , ]\n"
666 " <rotor_node_label>\n"
667 " (bool) <average> ,\n"
668 " <rotor_radius> ,\n"
669 " <blade_span>\n"
670 " [ , delay , (DriveCaller) <delay> ]\n"
671 " [ , omegacut , <cut_frequency> ]\n"
672 " [ , kappa , <hover_correction_coefficient> ]\n"
673 " [ , timestep , <time_step> ]\n"
674 " [ , <output_data> ]\n"
675 " ;\n"
676  << std::endl);
677 
678  if (!HP.IsArg()) {
679  /*
680  * Exit quietly if nothing else is provided
681  */
682  throw NoErr(MBDYN_EXCEPT_ARGS);
683  }
684  }
685 
686  if (!ReadRotorData(pDM, HP, uLabel, pCraft, RRot, pRotor)) {
688  }
689 
690  DriveCaller *pdW = 0;
691  doublereal dOmegaFilter;
692  doublereal dDeltaT;
693  if (!ReadUniform(pDM, HP, uLabel, bFlagAverage, dRadius, dSpan, pdW, dOmegaFilter, dKappa, dDeltaT)) {
695  }
696 
697  ppRes = ReadResSets(pDM, HP);
698 
700 
701  dArea = 2*dRadius*dSpan;
702  Weight.Set(pdW);
703 
704  SetFilterCoefficients(dOmegaFilter, dDeltaT);
705 }
706 
708 {
709  NO_OP;
710 }
711 
712 void
714 {
715  if (bToBeOutput()) {
716  OH.Loadable()
717  << std::setw(8) << GetLabel() /* 1 */
718  << " " << RRotorTranspose*Res.Force() /* 2-4 */
719  << " " << RRotorTranspose*Res.Moment() /* 5-7 */
720  << " " << dUindMean /* 8 */
721  << " " << dAzimuth /* 9 */
722  << " " << iStepCounter /* 10 */
723  << " " << "0." /* 11 */
724  << " " << "0." /* 12 */
725  << " " << "0." /* 13 */
726  << " " << FMeanOut /* 14 */
727  << std::endl;
728 
729  /* FIXME: check for parallel stuff ... */
730  for (int i = 0; ppRes && ppRes[i]; i++) {
731  OH.Loadable()
732  << std::setw(8) << GetLabel()
733  << ":" << ppRes[i]->GetLabel()
734  << " " << ppRes[i]->pRes->Force()
735  << " " << ppRes[i]->pRes->Moment()
736  << std::endl;
737  }
738  }
739 }
740 
741 void
743 {
744  bFlagIsFirstBlade = true;
745  /* calcolo la forza media sul giro generata dal rotore */
746  dTzMean += dTz;
747  FMean += F;
748  iStepCounter++;
749  // if ((dAzimuth > 0. && dAzimuthPrev < 0.) || (dAzimuth < 0. && dAzimuthPrev > 0.)) {
750  if ((dAzimuth > 0. && dAzimuthPrev < 0.)) {
751  FMean /= iStepCounter;
752  FMeanOut = FMean;
753  if (bFlagAverage) {
756  dUindMean = dKappa*copysign(std::sqrt(std::abs(dTzMean)/(2*dRho*dArea)), dTzMean);
758  dTzMean = 0.;
759  }
760  FMean = ::Zero3;
761  iStepCounter = 0;
762  }
764 
765  /* aggiorno ingressi e uscite del filtro */
766  Yk_2 = Yk_1;
767  Yk_1 = Yk;
768  Uk_2 = Uk_1;
769  Uk_1 = Uk;
770 
772 
773  dWeight = Weight.dGet();
774  if (dWeight < 0.) {
775  silent_cout("Rotor(" << GetLabel() << "): "
776  "delay < 0.0; using 0.0" << std::endl);
777  dWeight = 0.;
778  } else if (dWeight > 1.) {
779  silent_cout("Rotor(" << GetLabel() << "): "
780  "delay > 1.0; using 1.0" << std::endl);
781  dWeight = 1.;
782  }
783 
785 }
786 
789  doublereal dCoef,
790  const VectorHandler& XCurr,
791  const VectorHandler& XPrimeCurr)
792 {
793  /* UNIFORM induced velocity (Moble version)*/
794  /* Trasporta della matrice di rotazione del rotore */
795  RRotor = pCraft->GetRCurr()*RRot;
796  RRot3 = RRotor.GetVec(3);
798  /* Forze nel sistema rotore */
800  dTz = RRot3*Res.Force();
801  if (!bFlagAverage) {
802  /* filtro le forze */
803  Uk = dTz;
804  Yk = -Yk_1*a1 - Yk_2*a2 + Uk*b0 + Uk_1*b1 + Uk_2*b2;
805  dTz = Yk;
807  dUindMean = dKappa*copysign(std::sqrt(std::abs(dTz)/(2*dRho*dArea)), dTz);
808 
810  }
811 
812  ResetForce();
813  WorkVec.Resize(0);
814 
815  return WorkVec;
816 }
817 
818 void
819 CyclocopterUniform1D::AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X)
820 {
821 
822  /* colcolo la posizione azimutale della prima pala */
823  if (bFlagIsFirstBlade == true) {
824  Vec3 XRel(RRotorTranspose*(X - pRotor->GetXCurr()));
825  doublereal d1 = XRel(2);
826  doublereal d2 = XRel(3);
827  dAzimuth = atan2(d2, d1);
828  bFlagIsFirstBlade = false;
829  }
830 
831 
832  /* Sole se deve fare l'output calcola anche il momento */
833  if (bToBeOutput()) {
834  Res.AddForces(F, M, X);
835  InducedVelocity::AddForce(pEl, pNode, F, M, X);
836 
837  } else {
838  Res.AddForce(F);
839  }
840 }
841 
842 Vec3
844  unsigned uLabel, unsigned uPnt, const Vec3& X) const
845 {
846  return RRot3*dUindMean;
847 }
848 
849 /* CyclocopterUniform1D - end */
850 
851 /* CyclocopterUniform2D - begin */
852 
853 /*
854 
855 Uniform inflow: the induced velocity is opposite to
856 the force generated by the rotor in the plane
857 perdendicular to the rotor rotation axis. The
858 rotor reference must have direction 1 aligned
859 with the rotor rotation axis!
860 
861 */
862 
864 : virtual public Elem, public CyclocopterInflow {
865 protected:
868  mutable Vec3 dUindPrev;
869 
871 
873 
875 
876  unsigned int iStepCounter;
877 
878  /* dati per il filtraggio delle forze */
880 
881 public:
882  CyclocopterUniform2D(unsigned int uL, const DofOwner* pDO,
883  DataManager* pDM, MBDynParser& HP);
884  virtual ~CyclocopterUniform2D(void);
885 
886  // Elaborazione stato interno dopo la convergenza
887  virtual void
888  AfterConvergence(const VectorHandler& X, const VectorHandler& XP);
889 
890  // output; si assume che ogni tipo di elemento sappia,
891  // attraverso l'OutputHandler, dove scrivere il proprio output
892  virtual void Output(OutputHandler& OH) const;
893 
894  // assemblaggio residuo
895  virtual SubVectorHandler&
896  AssRes(SubVectorHandler& WorkVec,
897  doublereal dCoef,
898  const VectorHandler& XCurr,
899  const VectorHandler& XPrimeCurr);
900 
901  // Somma alla trazione il contributo di un elemento
902  virtual void
903  AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X);
904 
905  // Restituisce ad un elemento la velocita' indotta
906  // in base alla posizione azimuthale
907  virtual Vec3 GetInducedVelocity(Elem::Type type,
908  unsigned uLabel, unsigned uPnt, const Vec3& X) const;
909 
910  // Restituisce ad un elemento la velocità indotta
911  // in base alla posizione azimuthale (usata per
912  // iterare tra calcolo della valocità indotta e
913  // calcolo delle forze aerodinamiche - solo
914  // per il modello di influsso KARI per il ciclocottero)
915 #if 0
916  virtual void GetInducedVelocityIter(const Vec3& X, const Vec3& T, doublereal *UindM, doublereal dTn0, doublereal dTn_dUindM) {
917  NO_OP;
918  };
919 #endif
920 
921  // Restituisce la velocità indotta dalla metà superiore del rotore
922  // ( solo per KARI ciclocottero)
923  virtual doublereal GetW(const Vec3& X) const {
924  return 0.;
925  };
926 
927  virtual doublereal GetPsi(const Vec3& X) const {
928  return 0.;
929  };
930 
931  virtual Mat3x3 GetRRotor(const Vec3& X) const {
933  };
934 };
935 
937  DataManager* pDM, MBDynParser& HP)
938 : Elem(uL, flag(0)),
939 CyclocopterInflow(uL, pDO),
940 RRotor(::Eye3),
941 dUind(::Zero3), dUindPrev(::Zero3),
942 bFlagIsFirstBlade(true),
943 dAzimuth(0.), dAzimuthPrev(0.),
944 F(::Zero3), FMean(::Zero3), FMeanOut(::Zero3),
945 iStepCounter(0),
946 Uk(::Zero3), Uk_1(::Zero3), Uk_2(::Zero3), Yk(::Zero3), Yk_1(::Zero3), Yk_2(::Zero3)
947 {
948  if (HP.IsKeyWord("help")) {
949  silent_cout(
950 " \n"
951 "Module: Cyclocopter \n"
952 "Author: Pierangelo Masarati <pierangelo.masarati@polimi.it> \n"
953 "based on work by \n"
954 " Mattia Mattaboni <mattia.mattaboni@mail.polimi.it> \n"
955 "Organization: Dipartimento di Scienze e Tecnologie Aerospaziali \n"
956 " Politecnico di Milano \n"
957 " http://www.aero.polimi.it/ \n"
958 " Description: This module implements induced velocity models \n"
959 " for cycloidal rotors. \n"
960 " \n"
961 " All rights reserved. \n"
962 "\n"
963 " Usage:\n"
964 " user element: <label> , cycloidal uniform 2D ,\n"
965 " <aircraft_node_label> ,\n"
966 " [ orientation , (OrientationMatrix) <orientation> , ]\n"
967 " <rotor_node_label>\n"
968 " (bool) <average> ,\n"
969 " <rotor_radius> ,\n"
970 " <blade_span>\n"
971 " [ , delay , (DriveCaller) <delay> ]\n"
972 " [ , omegacut , <cut_frequency> ]\n"
973 " [ , kappa , <hover_correction_coefficient> ]\n"
974 " [ , timestep , <time_step> ]\n"
975 " [ , <output_data> ]\n"
976 " ;\n"
977  << std::endl);
978 
979  if (!HP.IsArg()) {
980  /*
981  * Exit quietly if nothing else is provided
982  */
983  throw NoErr(MBDYN_EXCEPT_ARGS);
984  }
985  }
986 
987  if (!ReadRotorData(pDM, HP, uLabel, pCraft, RRot, pRotor)) {
989  }
990 
991  DriveCaller *pdW = 0;
992  doublereal dOmegaFilter;
993  doublereal dDeltaT;
994  if (!ReadUniform(pDM, HP, uLabel, bFlagAverage, dRadius, dSpan, pdW, dOmegaFilter, dKappa, dDeltaT)) {
996  }
997 
998  ppRes = ReadResSets(pDM, HP);
999 
1001 
1002  dArea = 2*dRadius*dSpan;
1003  Weight.Set(pdW);
1004 
1005  SetFilterCoefficients(dOmegaFilter, dDeltaT);
1006 }
1007 
1009 {
1010  NO_OP;
1011 }
1012 
1013 void
1015 {
1016  if (bToBeOutput()) {
1017  OH.Loadable()
1018  << std::setw(8) << GetLabel() /* 1 */
1019  << " " << RRotorTranspose*Res.Force() /* 2-4 */
1020  << " " << RRotorTranspose*Res.Moment() /* 5-7 */
1021  << " " << dUindMean /* 8 */
1022  << " " << dAzimuth /* 9 */
1023  << " " << iStepCounter /* 10 */
1024  << " " << dUind /* 11-13 */
1025  << " " << FMeanOut /* 14-16 */
1026  << std::endl;
1027 
1028  /* FIXME: check for parallel stuff ... */
1029  for (int i = 0; ppRes && ppRes[i]; i++) {
1030  OH.Loadable()
1031  << std::setw(8) << GetLabel()
1032  << ":" << ppRes[i]->GetLabel()
1033  << " " << ppRes[i]->pRes->Force()
1034  << " " << ppRes[i]->pRes->Moment()
1035  << std::endl;
1036  }
1037  }
1038 
1039 }
1040 
1041 void
1043 {
1044  bFlagIsFirstBlade = true;
1045 #if 0
1046  if (bFlagAverage) {
1047  /* calcolo la forza media sul giro generata dal rotore */
1048  FMean = FMean + F;
1049  iStepCounter++;
1050  // if ((dAzimuth > 0. && dAzimuthPrev < 0.) || (dAzimuth < 0. && dAzimuthPrev > 0.)) {
1051  if ((dAzimuth > 0. && dAzimuthPrev < 0.)) {
1053  /* Forza nel piano normale all'asse di rotazione */
1054  doublereal dT = sqrt(FMean(2)*FMean(2) + FMean(3)*FMean(3));
1055  /* Velocità indotta: calcolata in base alla dT */
1057  dUindMean = sqrt(dT/(2*dRho*dArea));
1058  /* Componenti della velocità indotta nel sistema
1059  * rotore */
1060  dUind = 0.;
1061  if (dT > std::numeric_limits<doublereal>::epsilon()) {
1062  dUind(2) = dUindMean*FMean(2)/dT;
1063  dUind(3) = dUindMean*FMean(3)/dT;
1064  }
1065  dUind(1) = (1 - dWeight)*dUind(1) + dWeight*dUindPrev(1);
1066  dUind(2) = (1 - dWeight)*dUind(2) + dWeight*dUindPrev(2);
1067  dUind(3) = (1 - dWeight)*dUind(3) + dWeight*dUindPrev(3);
1068 
1069  FMean = 0.;
1070  iStepCounter = 0;
1071  }
1072  }
1073 #endif
1074 
1075  /* calcolo la forza media sul giro generata dal rotore */
1076  FMean = FMean + F;
1077  iStepCounter++;
1078  if ((dAzimuth > 0. && dAzimuthPrev < 0.)) {
1080  FMeanOut = FMean;
1081  if (bFlagAverage) {
1082  /* Forza nel piano normale all'asse di rotazione */
1083  doublereal dT = sqrt(FMean(2)*FMean(2) + FMean(3)*FMean(3));
1084  /* Velocità indotta: calcolata in base alla dT */
1086  dUindMean = dKappa*sqrt(dT/(2*dRho*dArea));
1087  /* Componenti della velocità indotta nel sistema
1088  * rotore */
1089  dUind = ::Zero3;
1090  if (dT > std::numeric_limits<doublereal>::epsilon()) {
1091  dUind(2) = dUindMean*FMean(2)/dT;
1092  dUind(3) = dUindMean*FMean(3)/dT;
1093  }
1094  dUind(1) = (1 - dWeight)*dUind(1) + dWeight*dUindPrev(1);
1095  dUind(2) = (1 - dWeight)*dUind(2) + dWeight*dUindPrev(2);
1096  dUind(3) = (1 - dWeight)*dUind(3) + dWeight*dUindPrev(3);
1097  }
1098 
1099  FMean = ::Zero3;
1100  iStepCounter = 0;
1101  }
1102 
1104 
1105  dUindPrev = dUind;
1106 
1107  /* aggiorno ingressi e uscite del filtro */
1108  Yk_2 = Yk_1;
1109  Yk_1 = Yk;
1110  Uk_2 = Uk_1;
1111  Uk_1 = Uk;
1112 
1113  dWeight = Weight.dGet();
1114  if (dWeight < 0.) {
1115  silent_cout("Rotor(" << GetLabel() << "): "
1116  "delay < 0.0; using 0.0" << std::endl);
1117  dWeight = 0.;
1118 
1119  } else if (dWeight > 1.) {
1120  silent_cout("Rotor(" << GetLabel() << "): "
1121  "delay > 1.0; using 1.0" << std::endl);
1122  dWeight = 1.;
1123  }
1124 
1126 }
1127 
1130  doublereal dCoef,
1131  const VectorHandler& XCurr,
1132  const VectorHandler& XPrimeCurr)
1133 {
1134  /* UNIFORM induced velocity */
1135  /* Trasporta della matrice di rotazione del rotore */
1136  RRotor = pCraft->GetRCurr()*RRot;
1138  /* Forze nel sistema rotore */
1139  F = RRotorTranspose*Res.Force();
1140  if (!bFlagAverage) {
1141  /* filtro le forze */
1142  Uk = F;
1143  Yk = -Yk_1*a1 - Yk_2*a2 + Uk*b0 + Uk_1*b1 + Uk_2*b2;
1144  F = Yk;
1145  /* Forza nel piano normale all'asse di rotazione */
1146  doublereal dT = sqrt(F(2)*F(2) + F(3)*F(3));
1147  /* Velocità indotta: calcolata in base alla dT */
1149  dUindMean = dKappa*sqrt(dT/(2*dRho*dArea));
1150  /* Componenti della velocità indotta nel sistema
1151  * rotore */
1152  dUind = ::Zero3;
1153  if (dT > std::numeric_limits<doublereal>::epsilon()) {
1154  dUind(2) = dUindMean*F(2)/dT;
1155  dUind(3) = dUindMean*F(3)/dT;
1156  }
1157  dUind(1) = (1 - dWeight)*dUind(1) + dWeight*dUindPrev(1);
1158  dUind(2) = (1 - dWeight)*dUind(2) + dWeight*dUindPrev(2);
1159  dUind(3) = (1 - dWeight)*dUind(3) + dWeight*dUindPrev(3);
1160 
1161  dUindMean = sqrt(dUind(1)*dUind(1) + dUind(2)*dUind(2) + dUind(3)*dUind(3));
1162  }
1163 
1164  ResetForce();
1165  WorkVec.Resize(0);
1166 
1167  return WorkVec;
1168 }
1169 
1170 void
1171 CyclocopterUniform2D::AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X)
1172 {
1173  /* colcolo la posizione azimutale della prima pala */
1174  // if (bFlagIsFirstBlade && bFlagAverage) {
1175  if (bFlagIsFirstBlade) {
1176  Vec3 XRel(RRotorTranspose*(X - pRotor->GetXCurr()));
1177  doublereal d1 = XRel(2);
1178  doublereal d2 = XRel(3);
1179  dAzimuth = atan2(d2, d1);
1180  bFlagIsFirstBlade = false;
1181  }
1182 
1183  /* Sole se deve fare l'output calcola anche il momento */
1184  if (bToBeOutput()) {
1185  Res.AddForces(F, M, X);
1186  InducedVelocity::AddForce(pEl, pNode, F, M, X);
1187 
1188  } else {
1189  Res.AddForce(F);
1190  }
1191 }
1192 
1193 Vec3
1195  unsigned uLabel, unsigned uPnt, const Vec3& X) const
1196 {
1197  //printf("%f %f %f\n",dUind(1),dUind(2),dUind(3));
1198  return RRotor*dUind;
1199 }
1200 
1201 /* CyclocopterUniform2D - end */
1202 
1203 
1204 /* CyclocopterPolimi - begin */
1205 
1206 /*
1207 
1208 The induced velocity is opposite to
1209 the force generated by the rotor in the plane
1210 perdendicular to the rotor rotation axis. The
1211 rotor reference must have direction 1 aligned
1212 with the rotor rotation axis!
1213 The inflow velocity distribution is constant along
1214 the cylinder span and is function of r:
1215 Vi(r) = Kc*cos((pi/2)*(r/R)) + Ks*sin(pi*(r/R))
1216 where the cofficients Kc and Ks are based on the
1217 momentum theory
1218 
1219 */
1220 
1222 : virtual public Elem, public CyclocopterInflow {
1223 protected:
1226  mutable Vec3 dUindPrev;
1227 
1229 
1231 
1233 
1235 
1236  unsigned int iStepCounter;
1237 
1238  /* dati per il filtraggio delle forze */
1240 
1241  unsigned int iCounter;
1242  unsigned int iRotationCounter;
1243 
1245 
1247 
1248 public:
1249  CyclocopterPolimi(unsigned int uL, const DofOwner* pDO,
1250  DataManager* pDM, MBDynParser& HP);
1251  virtual ~CyclocopterPolimi(void);
1252 
1253  // Elaborazione stato interno dopo la convergenza
1254  virtual void
1255  AfterConvergence(const VectorHandler& X, const VectorHandler& XP);
1256 
1257  // output; si assume che ogni tipo di elemento sappia,
1258  // attraverso l'OutputHandler, dove scrivere il proprio output
1259  virtual void Output(OutputHandler& OH) const;
1260 
1261  // assemblaggio residuo
1262  virtual SubVectorHandler&
1263  AssRes(SubVectorHandler& WorkVec,
1264  doublereal dCoef,
1265  const VectorHandler& XCurr,
1266  const VectorHandler& XPrimeCurr);
1267 
1268  // Somma alla trazione il contributo di un elemento
1269  virtual void
1270  AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X);
1271 
1272  // Restituisce ad un elemento la velocita' indotta
1273  // in base alla posizione azimuthale
1274  virtual Vec3 GetInducedVelocity(Elem::Type type,
1275  unsigned uLabel, unsigned uPnt, const Vec3& X) const;
1276 
1277  // Restituisce ad un elemento la velocità indotta
1278  // in base alla posizione azimuthale (usata per
1279  // iterare tra calcolo della valocità indotta e
1280  // calcolo delle forze aerodinamiche - solo
1281  // per il modello di influsso KARI per il ciclocottero)
1282 #if 0
1283  virtual void GetInducedVelocityIter(const Vec3& X, const Vec3& T, doublereal *UindM, doublereal dTn0, doublereal dTn_dUindM) {
1284  NO_OP;
1285  };
1286 #endif
1287 
1288  // Restituisce la velocità indotta dalla metà superiore del rotore
1289  // ( solo per KARI ciclocottero)
1290  virtual doublereal GetW(const Vec3& X) const {
1291  return 0.;
1292  };
1293 
1294  virtual doublereal GetPsi(const Vec3& X) const {
1295  return 0.;
1296  };
1297 
1298  virtual Mat3x3 GetRRotor(const Vec3& X) const {
1300  };
1301 };
1302 
1304  DataManager* pDM, MBDynParser& HP)
1305 : Elem(uL, flag(0)),
1306 CyclocopterInflow(uL, pDO),
1307 RRotor(::Eye3),
1308 dUind(::Zero3), dUindPrev(::Zero3),
1309 dXi(0.),
1310 bFlagIsFirstBlade(true),
1311 dAzimuth(0.), dAzimuthPrev(0.),
1312 F(::Zero3), FMean(::Zero3), FMeanOut(::Zero3),
1313 iStepCounter(0),
1314 Uk(::Zero3), Uk_1(::Zero3), Uk_2(::Zero3), Yk(::Zero3), Yk_1(::Zero3), Yk_2(::Zero3),
1315 iCounter(0), iRotationCounter(0),
1316 dpPrev(0.), dp(0.),
1317 flag_print(true)
1318 {
1319  if (HP.IsKeyWord("help")) {
1320  silent_cout(
1321 " \n"
1322 "Module: Cyclocopter \n"
1323 "Author: Pierangelo Masarati <pierangelo.masarati@polimi.it> \n"
1324 "based on work by \n"
1325 " Mattia Mattaboni <mattia.mattaboni@mail.polimi.it> \n"
1326 "Organization: Dipartimento di Scienze e Tecnologie Aerospaziali \n"
1327 " Politecnico di Milano \n"
1328 " http://www.aero.polimi.it/ \n"
1329 " Description: This module implements induced velocity models \n"
1330 " for cycloidal rotors. \n"
1331 " \n"
1332 " All rights reserved. \n"
1333 "\n"
1334 " Usage:\n"
1335 " user element: <label> , cycloidal Polimi ,\n"
1336 " <aircraft_node_label> ,\n"
1337 " [ orientation , (OrientationMatrix) <orientation> , ]\n"
1338 " <rotor_node_label>\n"
1339 " (bool) <average> ,\n"
1340 " <rotor_radius> ,\n"
1341 " <blade_span>\n"
1342 " [ , delay , (DriveCaller) <delay> ]\n"
1343 " [ , omegacut , <cut_frequency> ]\n"
1344 " [ , kappa , <hover_correction_coefficient> ]\n"
1345 " [ , timestep , <time_step> ]\n"
1346 " [ , <output_data> ]\n"
1347 " ;\n"
1348  << std::endl);
1349 
1350  if (!HP.IsArg()) {
1351  /*
1352  * Exit quietly if nothing else is provided
1353  */
1354  throw NoErr(MBDYN_EXCEPT_ARGS);
1355  }
1356  }
1357 
1358  if (!ReadRotorData(pDM, HP, uLabel, pCraft, RRot, pRotor)) {
1360  }
1361 
1362  DriveCaller *pdW = 0;
1363  doublereal dOmegaFilter;
1364  doublereal dDeltaT;
1365  if (!ReadUniform(pDM, HP, uLabel, bFlagAverage, dRadius, dSpan, pdW, dOmegaFilter, dKappa, dDeltaT)) {
1367  }
1368 
1369  ppRes = ReadResSets(pDM, HP);
1370 
1372 
1373  dArea = 2*dRadius*dSpan;
1374  Weight.Set(pdW);
1375 
1376  SetFilterCoefficients(dOmegaFilter, dDeltaT);
1377 }
1378 
1380 {
1381  NO_OP;
1382 }
1383 
1384 void
1386 {
1387  bFlagIsFirstBlade = true;
1388  /* calcolo la forza media sul giro generata dal rotore */
1389  FMean = FMean + F;;
1390  iStepCounter++;
1391  // if ((dAzimuth > 0. && dAzimuthPrev < 0.) || (dAzimuth < 0. && dAzimuthPrev > 0.)) {
1392  if ((dAzimuth > 0. && dAzimuthPrev < 0.)) {
1394  FMeanOut = FMean;
1395  if (bFlagAverage) {
1396  /* Forza nel piano normale all'asse di rotazione */
1397  doublereal dT = sqrt(FMean(2)*FMean(2) + FMean(3)*FMean(3));
1398  /* Velocità indotta: calcolata in base alla dT */
1400  dUindMean = dKappa*sqrt(dT/(2*dRho*dArea));
1401  /* Componenti della velocità indotta nel sistema
1402  * rotore */
1403  dUind = Zero3;
1404  if (dT > std::numeric_limits<doublereal>::epsilon()) {
1405  dUind(2) = dUindMean*FMean(2)/dT;
1406  dUind(3) = dUindMean*FMean(3)/dT;
1407  }
1408  dUind(1) = (1 - dWeight)*dUind(1) + dWeight*dUindPrev(1);
1409  dUind(2) = (1 - dWeight)*dUind(2) + dWeight*dUindPrev(2);
1410  dUind(3) = (1 - dWeight)*dUind(3) + dWeight*dUindPrev(3);
1411  /* angolo di cui è ruotata la trazione */
1412  dXi = atan2(FMean(3), FMean(2)) - M_PI/2.;
1413  }
1414 
1415  FMean = Zero3;
1416  iStepCounter = 0;
1417  }
1418 
1420 
1421  dUindPrev = dUind;
1422 
1423  /* aggiorno ingressi e uscite del filtro */
1424  Yk_2 = Yk_1;
1425  Yk_1 = Yk;
1426  Uk_2 = Uk_1;
1427  Uk_1 = Uk;
1428 
1429  dWeight = Weight.dGet();
1430  if (dWeight < 0.) {
1431  silent_cout("Rotor(" << GetLabel() << "): "
1432  "delay < 0.0; using 0.0" << std::endl);
1433  dWeight = 0.;
1434 
1435  } else if (dWeight > 1.) {
1436  silent_cout("Rotor(" << GetLabel() << "): "
1437  "delay > 1.0; using 1.0" << std::endl);
1438  dWeight = 1.;
1439  }
1440 
1442 }
1443 
1444 void
1446 {
1447  if (bToBeOutput()) {
1448  OH.Loadable()
1449  << std::setw(8) << GetLabel() /* 1 */
1450  << " " << RRotorTranspose*Res.Force() /* 2-4 */
1451  << " " << RRotorTranspose*Res.Moment() /* 5-7 */
1452  << " " << dUindMean /* 8 */
1453  << " " << dUind /* 9 -11*/
1454  << " " << dXi /* 12 */
1455  << " " << dAzimuth /* 13 */
1456  << " " << FMeanOut /* 14-16 */
1457  << std::endl;
1458 
1459  /* FIXME: check for parallel stuff ... */
1460  for (int i = 0; ppRes && ppRes[i]; i++) {
1461  OH.Loadable()
1462  << std::setw(8) << GetLabel()
1463  << ":" << ppRes[i]->GetLabel()
1464  << " " << ppRes[i]->pRes->Force()
1465  << " " << ppRes[i]->pRes->Moment()
1466  << std::endl;
1467  }
1468  }
1469 }
1470 
1473  doublereal dCoef,
1474  const VectorHandler& XCurr,
1475  const VectorHandler& XPrimeCurr)
1476 {
1477  /* UNIFORM induced velocity */
1478  /* Trasporta della matrice di rotazione del rotore */
1479  RRotor = pCraft->GetRCurr()*RRot;
1481  /* Forze nel sistema rotore */
1482  F = RRotorTranspose*Res.Force();
1483  if (!bFlagAverage) {
1484  /* filtro le forze */
1485  Uk = F;
1486  Yk = -Yk_1*a1 - Yk_2*a2 + Uk*b0 + Uk_1*b1 + Uk_2*b2;
1487  F = Yk;
1488  /* Forza nel piano normale all'asse di rotazione */
1489  doublereal dT = sqrt(F(2)*F(2) + F(3)*F(3));
1490  /* Velocità indotta: calcolata in base alla dT */
1492  dUindMean = dKappa*sqrt(dT/(2*dRho*dArea));
1493  /* Componenti della velocità indotta nel sistema
1494  * rotore */
1495  dUind = Zero3;
1496  if (dT > std::numeric_limits<doublereal>::epsilon()) {
1497  dUind(2) = dUindMean*F(2)/dT;
1498  dUind(3) = dUindMean*F(3)/dT;
1499  }
1500  dUind(1) = (1 - dWeight)*dUind(1) + dWeight*dUindPrev(1);
1501  dUind(2) = (1 - dWeight)*dUind(2) + dWeight*dUindPrev(2);
1502  dUind(3) = (1 - dWeight)*dUind(3) + dWeight*dUindPrev(3);
1503 
1504  dUindMean = sqrt(dUind(1)*dUind(1) + dUind(2)*dUind(2) + dUind(3)*dUind(3));
1505  /* angolo di cui è ruotata la trazione */
1506  dXi = atan2(F(3), F(2)) - M_PI/2.;
1507  }
1508 
1509  ResetForce();
1510  WorkVec.Resize(0);
1511 
1512  return WorkVec;
1513 }
1514 
1515 void
1516 CyclocopterPolimi::AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X)
1517 {
1518  /* colcolo la posizione azimutale della prima pala */
1519  if (bFlagIsFirstBlade) {
1520  Vec3 XRel(RRotorTranspose*(X - pRotor->GetXCurr()));
1521  doublereal d1 = XRel(2);
1522  doublereal d2 = XRel(3);
1523  dAzimuth = atan2(d2, d1);
1524  bFlagIsFirstBlade = false;
1525  }
1526 
1527  /* Sole se deve fare l'output calcola anche il momento */
1528  if (bToBeOutput()) {
1529  Res.AddForces(F,M,X);
1530  InducedVelocity::AddForce(pEl, pNode, F, M, X);
1531 
1532  } else {
1533  Res.AddForce(F);
1534  }
1535 }
1536 
1537 Vec3
1539  unsigned uLabel, unsigned uPnt, const Vec3& X) const
1540 {
1541  Vec3 XRel(RRotorTranspose*(X - pRotor->GetXCurr()));
1542 
1543  doublereal d1 = XRel(2);
1544  doublereal d2 = XRel(3);
1545 
1546  /* dPsi0 non serve a nulla perchè uso l'angolo
1547  * relativo: (dp-dXi)!!! */
1548  doublereal dpp = atan2(d2, d1);
1549 
1550  doublereal r = sqrt(d1*d1 + d2*d2)*cos(dpp - dXi);
1551 
1552  return RRotor*((dUind*(M_PI/2.))*cos((M_PI/2.)*(r/dRadius)));
1553 }
1554 
1555 /* CyclocopterPolimi - end */
1556 
1557 #if 0 // KARI NOT IMPLEMENTED YET!
1558 
1559 /* CyclocopterKARI - begin */
1560 
1561 /*
1562 
1563 From:
1564 
1565 "A New VTOL UAV Cyclocopter with Cycloidal Blades System",
1566 
1567 Chul Yong Yun, Illkyung Park,
1568 Ho Yong Lee, Jai Sang Jung, In Seong Hwang,
1569 Seung Jo Kim,
1570 Sung Nam Jung
1571 
1572 Presented at the American Helicopter Society 60th Annual Forum,
1573 Baltimore, MD, June 7-10, 2004.
1574 */
1575 
1576 class CyclocopterKARI
1577 : virtual public Elem, public CyclocopterInflow {
1578 public:
1579  CyclocopterKARI(unsigned int uL, const DofOwner* pDO,
1580  DataManager* pDM, MBDynParser& HP);
1581  virtual ~CyclocopterKARI(void);
1582 
1583  // Elaborazione stato interno dopo la convergenza
1584  virtual void
1585  AfterConvergence(const VectorHandler& X, const VectorHandler& XP);
1586 
1587  // output; si assume che ogni tipo di elemento sappia,
1588  // attraverso l'OutputHandler, dove scrivere il proprio output
1589  virtual void Output(OutputHandler& OH) const;
1590 
1591  // Contributo al file di Restart
1592  virtual std::ostream& Restart(std::ostream& out) const;
1593 
1594  // assemblaggio residuo
1595  virtual SubVectorHandler&
1596  AssRes(SubVectorHandler& WorkVec,
1597  doublereal dCoef,
1598  const VectorHandler& XCurr,
1599  const VectorHandler& XPrimeCurr);
1600 
1601 #if 0
1602  // Somma alla trazione il contributo di un elemento
1603  virtual void
1604  AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X);
1605 #endif
1606 
1607  // Restituisce ad un elemento la velocita' indotta
1608  // in base alla posizione azimuthale
1609  virtual Vec3 GetInducedVelocity(Elem::Type type,
1610  unsigned uLabel, unsigned uPnt, const Vec3& X) const;
1611 
1612  // *******PER IL SOLUTORE PARALLELO********
1613  // Fornisce il tipo e la label dei nodi che sono connessi all'elemento
1614  // utile per l'assemblaggio della matrice di connessione fra i dofs
1615  virtual void
1616  GetConnectedNodes(std::vector<const Node *>& connectedNodes) const;
1617  // ************************************************
1618 };
1619 
1620 CyclocopterKARI::CyclocopterKARI(unsigned int uL, const DofOwner* pDO,
1621  DataManager* pDM, MBDynParser& HP)
1622 : Elem(uL, 0),
1623 CyclocopterInflow(uL, pDO),
1624 pRotor(0),
1625 RRot(::Eye3)
1626 {
1627  if (!ReadRotorData(pDM, HP, uLabel, pCraft, RRot, pRotor)) {
1629  }
1630 
1631  ppRes = ReadResSets(pDM, HP);
1632 
1634 }
1635 
1636 CyclocopterKARI::~CyclocopterKARI(void)
1637 {
1638  NO_OP;
1639 }
1640 
1641 void
1642 CyclocopterKARI::AfterConvergence(const VectorHandler& X, const VectorHandler& XP)
1643 {
1644  NO_OP;
1645 }
1646 
1647 void
1648 CyclocopterKARI::Output(OutputHandler& OH) const
1649 {
1650  NO_OP;
1651 }
1652 
1653 std::ostream&
1654 CyclocopterKARI::Restart(std::ostream& out) const
1655 {
1656  return out << "# cyclocopter: not implemented yet" << std::endl;
1657 }
1658 
1660 CyclocopterKARI::AssRes(SubVectorHandler& WorkVec,
1661  doublereal dCoef,
1662  const VectorHandler& XCurr,
1663  const VectorHandler& XPrimeCurr)
1664 {
1665  return WorkVec;
1666 }
1667 
1668 #if 0
1669 void
1670 CyclocopterKARI::AddForce(const Elem *pEl, const StructNode *pNode, const Vec3& F, const Vec3& M, const Vec3& X)
1671 {
1672  NO_OP;
1673 }
1674 #endif
1675 
1676 Vec3
1677 CyclocopterKARI::GetInducedVelocity(Elem::Type type,
1678  unsigned uLabel, unsigned uPnt, const Vec3& X) const
1679 {
1680  return Zero3;
1681 }
1682 
1683 void
1684 CyclocopterKARI::GetConnectedNodes(std::vector<const Node *>& connectedNodes) const
1685 {
1686  connectedNodes.resize(1);
1687  connectedNodes[0] = pCraft;
1688 }
1689 
1690 /* CyclocopterKARI - end */
1691 
1692 #endif // KARI NOT IMPLEMENTED YET!
1693 
1694 bool
1696 {
1697  UserDefinedElemRead *rf;
1698 
1700  if (!SetUDE("cyclocopter" "no" "inflow", rf)) {
1701  delete rf;
1702 
1703  silent_cerr("module-cyclocopter: "
1704  "unable to register \"cyclocopter no inflow\""
1705  << std::endl);
1706 
1707  return false;
1708  }
1709 
1711  if (!SetUDE("cyclocopter" "uniform" "1D", rf)) {
1712  delete rf;
1713 
1714  silent_cerr("module-cyclocopter: "
1715  "unable to register \"cyclocopter uniform 1D\""
1716  << std::endl);
1717 
1718  return false;
1719  }
1720 
1722  if (!SetUDE("cyclocopter" "uniform" "2D", rf)) {
1723  delete rf;
1724 
1725  silent_cerr("module-cyclocopter: "
1726  "unable to register \"cyclocopter uniform 2D\""
1727  << std::endl);
1728 
1729  return false;
1730  }
1731 
1732  rf = new UDERead<CyclocopterPolimi>;
1733  if (!SetUDE("cyclocopter" "Polimi", rf)) {
1734  delete rf;
1735 
1736  silent_cerr("module-cyclocopter: "
1737  "unable to register \"cyclocopter Polimi\""
1738  << std::endl);
1739 
1740  return false;
1741  }
1742 
1743 #if 0
1744  rf = new UDERead<CyclocopterKARI>;
1745  if (!SetUDE("cyclocopter" "KARI", rf)) {
1746  delete rf;
1747 
1748  silent_cerr("module-cyclocopter: "
1749  "unable to register \"cyclocopter KARI\""
1750  << std::endl);
1751 
1752  return false;
1753  }
1754 #endif
1755 
1756  return true;
1757 }
1758 
1759 #ifdef MBDYN_MODULE
1760 
1761 extern "C" int
1762 module_init(const char *module_name, void *pdm, void *php)
1763 {
1764  if (!mbdyn_cyclocopter_set()) {
1765  silent_cerr("cyclocopter: "
1766  "module_init(" << module_name << ") "
1767  "failed" << std::endl);
1768  return -1;
1769  }
1770 
1771  return 0;
1772 }
1773 
1774 #endif // MBDYN_MODULE
flag fReadOutput(MBDynParser &HP, const T &t) const
Definition: dataman.h:1064
ExternResForces Res
Definition: indvel.h:114
virtual doublereal dGetAirDensity(const Vec3 &X) const
Definition: aerodyn.cc:736
Mat3x3 GetRotRel(const ReferenceFrame &rf)
Definition: mbpar.cc:1795
virtual void AfterConvergence(const VectorHandler &X, const VectorHandler &XP)
Definition: indvel.cc:170
void SetFilterCoefficients(doublereal dOmegaFilter, doublereal dDeltaT)
CyclocopterUniform2D(unsigned int uL, const DofOwner *pDO, DataManager *pDM, MBDynParser &HP)
#define M_PI
Definition: gradienttest.cc:67
const Vec3 Zero3(0., 0., 0.)
virtual void Output(OutputHandler &OH) const
virtual void Output(OutputHandler &OH) const
long int flag
Definition: mbdyn.h:43
virtual bool bToBeOutput(void) const
Definition: output.cc:890
virtual void ResetForce(void)
Definition: indvel.cc:276
#define MBDYN_EXCEPT_ARGS
Definition: except.h:63
Definition: matvec3.h:98
virtual void Output(OutputHandler &OH) const
ResForceSet ** ppRes
Definition: indvel.h:116
virtual void ResizeReset(integer)
Definition: vh.cc:55
unsigned int iRotationCounter
virtual doublereal GetW(const Vec3 &X) const
virtual const Mat3x3 & GetRCurr(void) const
Definition: strnode.h:1012
virtual doublereal GetPsi(const Vec3 &X) const
virtual Vec3 GetInducedVelocity(Elem::Type type, unsigned uLabel, unsigned uPnt, const Vec3 &X) const
virtual doublereal GetPsi(const Vec3 &X) const
virtual const Vec3 & Force(void) const
Definition: resforces.cc:103
virtual Vec3 GetInducedVelocity(Elem::Type type, unsigned uLabel, unsigned uPnt, const Vec3 &X) const
const Mat3x3 Eye3(1., 0., 0., 0., 1., 0., 0., 0., 1.)
virtual void GetConnectedNodes(std::vector< const Node * > &connectedNodes) const
VariableSubMatrixHandler & InitialAssJac(VariableSubMatrixHandler &WorkMat, const VectorHandler &XCurr)
virtual ~CyclocopterPolimi(void)
#define NO_OP
Definition: myassert.h:74
std::vector< Hint * > Hints
Definition: simentity.h:89
virtual const Vec3 & Moment(void) const
Definition: resforces.cc:109
virtual const Vec3 & GetXCurr(void) const
Definition: indvel.h:159
Vec3 GetVec(unsigned short int i) const
Definition: matvec3.h:893
virtual void SetInitialValue(VectorHandler &X)
virtual unsigned int iGetInitialNumDof(void) const
virtual bool GetYesNoOrBool(bool bDefval=false)
Definition: parser.cc:1038
virtual ~CyclocopterInflow(void)
static bool ReadRotorData(DataManager *pDM, MBDynParser &HP, unsigned int uLabel, const StructNode *&pCraft, Mat3x3 &rrot, const StructNode *&pRotor)
virtual void Output(OutputHandler &OH) const
virtual Elem::Type GetElemType(void) const
const Mat3x3 Zero3x3(0., 0., 0., 0., 0., 0., 0., 0., 0.)
virtual doublereal GetW(const Vec3 &X) const
virtual void AddForce(const Elem *pEl, const StructNode *pNode, const Vec3 &F, const Vec3 &M, const Vec3 &X)
Definition: indvel.cc:252
CyclocopterInflow(unsigned int uL, const DofOwner *pDO)
void AddForces(const Vec3 &f, const Vec3 &c, const Vec3 &x)
Definition: resforces.cc:77
virtual SubVectorHandler & AssRes(SubVectorHandler &WorkVec, doublereal dCoef, const VectorHandler &XCurr, const VectorHandler &XPrimeCurr)
virtual doublereal GetPsi(const Vec3 &X) const
#define SAFENEW(pnt, item)
Definition: mynewmem.h:695
virtual std::ostream & Restart(std::ostream &out) const
const StructNode * pRotor
void SetNullMatrix(void)
Definition: submat.h:1159
Definition: mbdyn.h:76
virtual bool IsKeyWord(const char *sKeyWord)
Definition: parser.cc:910
int module_init(const char *module_name, void *pdm, void *php)
std::ostream & Loadable(void) const
Definition: output.h:506
virtual ~CyclocopterUniform1D(void)
virtual ~CyclocopterUniform2D(void)
CyclocopterNoInflow(unsigned int uL, const DofOwner *pDO, DataManager *pDM, MBDynParser &HP)
virtual InducedVelocity::Type GetInducedVelocityType(void) const
virtual Vec3 GetInducedVelocity(Elem::Type type, unsigned uLabel, unsigned uPnt, const Vec3 &X) const =0
CyclocopterPolimi(unsigned int uL, const DofOwner *pDO, DataManager *pDM, MBDynParser &HP)
doublereal copysign(doublereal x, doublereal y)
Definition: gradient.h:97
virtual void AddForce(const Elem *pEl, const StructNode *pNode, const Vec3 &F, const Vec3 &M, const Vec3 &X)
static bool ReadUniform(DataManager *pDM, MBDynParser &HP, unsigned int uLabel, bool &bFlagAve, doublereal &dR, doublereal &dL, DriveCaller *&pdW, doublereal &dOmegaFilter, doublereal &dKappa, doublereal &dDeltaT)
Definition: mbdyn.h:77
virtual SubVectorHandler & AssRes(SubVectorHandler &WorkVec, doublereal dCoef, const VectorHandler &XCurr, const VectorHandler &XPrimeCurr)
CyclocopterUniform1D(unsigned int uL, const DofOwner *pDO, DataManager *pDM, MBDynParser &HP)
unsigned int uLabel
Definition: withlab.h:44
#define ASSERT(expression)
Definition: colamd.c:977
virtual void AfterConvergence(const VectorHandler &X, const VectorHandler &XP)
GradientExpression< UnaryExpr< FuncSqrt, Expr > > sqrt(const GradientExpression< Expr > &u)
Definition: gradient.h:2974
virtual const Vec3 & GetXCurr(void) const
Definition: strnode.h:310
ResForceSet ** ReadResSets(DataManager *pDM, MBDynParser &HP)
Definition: resforces.cc:263
virtual Vec3 GetInducedVelocity(Elem::Type type, unsigned uLabel, unsigned uPnt, const Vec3 &X) const
Definition: except.h:79
virtual Mat3x3 GetRRotor(const Vec3 &X) const
virtual void SetValue(DataManager *pDM, VectorHandler &X, VectorHandler &XP, SimulationEntity::Hints *ph)
virtual Mat3x3 GetRRotor(const Vec3 &X) const
Mat3x3 Transpose(void) const
Definition: matvec3.h:816
void AddForce(const Vec3 &f)
Definition: resforces.cc:58
virtual bool IsArg(void)
Definition: parser.cc:807
Definition: elem.h:75
virtual Vec3 GetInducedVelocity(Elem::Type type, unsigned uLabel, unsigned uPnt, const Vec3 &X) const
Type
Definition: elem.h:91
bool SetUDE(const std::string &s, UserDefinedElemRead *rude)
Definition: userelem.cc:97
void Set(const DriveCaller *pDC)
Definition: drive.cc:647
virtual doublereal GetPsi(const Vec3 &X) const
doublereal dGet(const doublereal &dVar) const
Definition: drive.cc:664
virtual void AfterConvergence(const VectorHandler &X, const VectorHandler &XP)
virtual SubVectorHandler & AssRes(SubVectorHandler &WorkVec, doublereal dCoef, const VectorHandler &XCurr, const VectorHandler &XPrimeCurr)=0
virtual void InitialWorkSpaceDim(integer *piNumRows, integer *piNumCols) const
bool mbdyn_cyclocopter_set(void)
virtual ~CyclocopterNoInflow(void)
virtual doublereal GetW(const Vec3 &X) const
GradientExpression< UnaryExpr< FuncCos, Expr > > cos(const GradientExpression< Expr > &u)
Definition: gradient.h:2978
virtual void AddForce(const Elem *pEl, const StructNode *pNode, const Vec3 &F, const Vec3 &M, const Vec3 &X)
DriveCaller * GetDriveCaller(bool bDeferred=false)
Definition: mbpar.cc:2033
virtual void AfterConvergence(const VectorHandler &X, const VectorHandler &XP)
virtual Mat3x3 GetRRotor(const Vec3 &X) const
virtual Mat3x3 GetRRotor(const Vec3 &X) const
virtual void AddForce(const Elem *pEl, const StructNode *pNode, const Vec3 &F, const Vec3 &M, const Vec3 &X)
SubVectorHandler & InitialAssRes(SubVectorHandler &WorkVec, const VectorHandler &XCurr)
virtual void AddForce(const Elem *pEl, const StructNode *pNode, const Vec3 &F, const Vec3 &M, const Vec3 &X)
virtual void SetOutputFlag(flag f=flag(1))
Definition: output.cc:896
GradientExpression< BinaryExpr< FuncAtan2, LhsExpr, RhsExpr > > atan2(const GradientExpression< LhsExpr > &u, const GradientExpression< RhsExpr > &v)
Definition: gradient.h:2962
double doublereal
Definition: colamd.c:52
virtual SubVectorHandler & AssRes(SubVectorHandler &WorkVec, doublereal dCoef, const VectorHandler &XCurr, const VectorHandler &XPrimeCurr)
long int integer
Definition: colamd.c:51
virtual HighParser::ErrOut GetLineData(void) const
Definition: parsinc.cc:697
unsigned int GetLabel(void) const
Definition: withlab.cc:62
virtual void AfterConvergence(const VectorHandler &X, const VectorHandler &XP)
Node * ReadNode(MBDynParser &HP, Node::Type type) const
Definition: dataman3.cc:2309
virtual doublereal GetW(const Vec3 &X) const
virtual SubVectorHandler & AssRes(SubVectorHandler &WorkVec, doublereal dCoef, const VectorHandler &XCurr, const VectorHandler &XPrimeCurr)
virtual void Resize(integer iNewSize)=0
const StructNode * pCraft
Definition: indvel.h:111
virtual doublereal GetReal(const doublereal &dDefval=0.0)
Definition: parser.cc:1056