Code_TYMPAN  4.2.0
Industrial site acoustic simulation
Lancer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012> <EDF-R&D> <FRANCE>
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10  * See the GNU General Public License for more details.
11  * You should have received a copy of the GNU General Public License along
12  * with this program; if not, write to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
14 */
15 
16 
22 
23 #include "meteo.h"
24 #include "meteoLin.h"
25 #include "RayCourb.h"
26 #include "Lancer.h"
27 
28 Lancer::Lancer() : sources(std::vector<vec3>()), recepteurs(std::vector<vec3>()),_weather(NULL), _sampler(NULL), h(0.001f), TMax(3.0f), temps(std::vector<decimal>()), dmax(1000.f), nbRay(20)
29 {
30  _weather = new meteoLin();
31  initialAngleTheta = 0.0;
32  finalAngleTheta = 360.0;
33  initialAnglePhi = 0.0;
34  finalAnglePhi = 360.0;
36  _launchType = 1;
37  wantOutFile = true;
38 }
39 
40 
42 {
43  sources = L.sources;
45  _plan = L._plan;
46  _weather = L._weather;
47  h = L.h;
48  TMax = L.TMax;
49  temps = L.temps;
50  dmax = L.dmax;
51  nbRay = L.nbRay;
52  MatRes = L.MatRes;
53 
58 
61 }
62 
64 {
65  purgeMatRes();
66 }
67 
69 {
70  switch (_launchType)
71  {
72  case 1 : // Tir horizontal
74  _sampler->init();
75  dynamic_cast<Latitude2DSampler*>(_sampler)->setStartTheta(initialAngleTheta);
76  dynamic_cast<Latitude2DSampler*>(_sampler)->setStartPhi(initialAnglePhi);
77  dynamic_cast<Latitude2DSampler*>(_sampler)->setEndPhi(finalAnglePhi);
78  break;
79  case 2 : // Tir vertical
81  _sampler->init();
82  dynamic_cast<Longitude2DSampler*>(_sampler)->setStartTheta(initialAngleTheta);
83  dynamic_cast<Longitude2DSampler*>(_sampler)->setEndTheta(finalAngleTheta);
84  dynamic_cast<Longitude2DSampler*>(_sampler)->setStartPhi(initialAnglePhi);
85  break;
86  case 3 : // Tir sur une sphere
88  _sampler->init();
89  nbRay = dynamic_cast<UniformSphericSampler*>(_sampler)->getRealNbRays();
90  break;
91  case 4 : // Tir sur une sphere v2
93  _sampler->init();
94  nbRay = dynamic_cast<UniformSphericSampler2*>(_sampler)->getRealNbRays();
95  break;
96  default :
97  return; // do nothing
98  }
99 
100 
101 }
102 
104 {
105  // Nettoyage de la matrice resultat
106  for (unsigned int i = 0; i < MatRes.size(); i++)
107  {
108  if (MatRes[i]) { delete [] MatRes[i]; }
109  MatRes[i] = NULL;
110  }
111  MatRes.clear();
112 }
113 
114 Step Lancer::EqRay(const Step& y0) // Fonction definissant le probleme a resoudre
115 {
116  Step y;
117  vec3 n;
118 
119  // calcul des variables de celerite et de son gradient, de la vitesse du vent et de sa derive
120  vec3 Dc = vec3();
121  decimal c = (decimal)dynamic_cast<meteoLin*>(_weather)->cTemp(y0.pos, Dc);
122 
123  //map<pair<int, int>, decimal> Jv;
124  const array< array<double, 3>, 3 >& Jv = dynamic_cast<meteoLin*>(_weather)->getJacobMatrix();
125  vec3 v = dynamic_cast<meteoLin*>(_weather)->cWind(y0.pos);
126 
127  // definition de s (normale normalisee selon la celerite effective) et de Omega
128  vec3 s = y0.norm;
129  decimal omega = 1 - (v * s);
130 
131  // on calcule les coordonnees
132  y.pos = ((s * (c * c / omega)) + v); //(c * c / omega * s + v)
133 
134  // On calcule les normales
135  n.x = (decimal)(- omega / c * Dc.x - Jv[0][0] * s.x - Jv[0][1] * s.y - Jv[0][2] * s.z);
136  n.y = (decimal)(- omega / c * Dc.y - Jv[1][0] * s.x - Jv[1][1] * s.y - Jv[1][2] * s.z);
137  n.z = (decimal)(- omega / c * Dc.z - Jv[2][0] * s.x - Jv[2][1] * s.y - Jv[2][2] * s.z);
138 
139  n.x += (decimal)((Jv[0][1] - Jv[1][0]) * s.y + (Jv[0][2] - Jv[2][0]) * s.z);
140  n.y += (decimal)((Jv[1][2] - Jv[2][1]) * s.z + (Jv[1][0] - Jv[0][1]) * s.x);
141  n.z += (decimal)((Jv[2][0] - Jv[0][2]) * s.x + (Jv[2][1] - Jv[1][2]) * s.y);
142 
143  y.norm = n;
144 
145  return y;
146 }
147 
148 
149 
151 {
152  /*
153  Pour une source donnee, a chaque pas de temps :
154  - on calcule le point suivant par l'algorithme de Runge-Kutta d'ordre 4,
155  - on regarde si le rayon rencontre ou non une face (reflexion), si c'est le cas, on enregistre la position de la reflexion (indice) et on incremente le compteur du nombre de
156  reflexion.
157 
158  Les calculs se finissent soit quand on depasse le temps d'execution maximal, soit lorsque l'on depasse la distance maximale fixes par l'utilisateur.
159 
160  La methode rend un rayon courbe.
161  */
162 
163  decimal travel_length = 0.;
164 
165  RayCourb y;
166  y.setSize(temps.size() + 10);
167 
168  /* on definit deux vectors : un "actuel" et un "suivant" car la methode de Runge-Kutta est une methode de resolution explicite a un pas de temps */
169  Step yAct(y0);
170  Step ySuiv;
171  int cpt_tps = 0; // compteur de temps
172 
173  // Les premieres valeurs correspondent a notre source.
174  y.etapes.push_back(yAct);
175 
176  // on remplit le reste avec notre fonction EqRay qui definit notre probleme
177 
178  while ((static_cast<unsigned int>(cpt_tps) < temps.size()) && (travel_length < dmax))
179  {
180  // On definit deux variables qui vont nous servir a garder en memoire les valeurs minimales du point d'intersection
181  // Car on parcourt les objets dans l'ordre ou ils sont ranges mais il se peut qu'un objet A plus pres du point considere se trouve apres un objet B plus loin
182  // et quand on boucle, si on sort des la premiere intersection, la reponse sera l'intersection avec B alors que dans la realite, c'est avec l'objet A qu'il y a une intersection.
183 
184  ySuiv = compute_next_step(yAct);
185 
186  // Recherche des intersections
187  intersection(cpt_tps, y, yAct, ySuiv);
188 
189  // on remplit maintenant notre rayon
190  y.etapes.push_back(ySuiv);
191 
192  // on met a jour nos variables
193  travel_length += ySuiv.pos.distance(yAct.pos); // distance parcourue par le rayon
194 
195  yAct = ySuiv;
196  cpt_tps++;
197  }
198 
199  return y;
200 }
201 
203 {
204  /* Methode pour remplir la matrice des resultats.*/
205 
206  assert(nbRay > 0); // on verifie que l'on souhaite bien lancer au moins un rayon.
207  vec3 grad, s0, n0;
208  //map< pair<int, int>, decimal > jacob;
209  Step y0;
210 
211  RayCourb* tab = NULL;
212 
213  for (unsigned int ns = 0; ns < sources.size(); ++ns)
214  {
215  vec3& source = sources[ns];
216  y0.pos = source;
217  tab = new RayCourb[nbRay];
218 
219  for (unsigned int k = 0; k < nbRay; ++k)
220  {
221  n0 = _sampler->getSample();
222 
223  s0 = n0 / (decimal)((dynamic_cast<meteoLin*>(_weather)->cTemp(source, grad) + (dynamic_cast<meteoLin*>(_weather)->cWind(source) * n0)));
224  y0.norm = s0;
225 
226  // on resoud l'equation par la methode de runge-kutta d'ordre 4
227  tab[k] = RK4(y0);
228  }
229 
230  MatRes.push_back(tab);
231  tab = NULL;
232  }
233  assert(MatRes.size() == sources.size());
234 
235  if (wantOutFile) { save(); }
236 }
237 
238 Step Lancer::compute_next_step(const Step& current_step)
239 {
240  Step k1, k2, k3, k4;
241 
242  k1 = EqRay(current_step) * h;
243  k2 = EqRay(current_step + k1 * 0.5) * h;
244  k3 = EqRay(current_step + k2 * 0.5) * h;
245  k4 = EqRay(current_step + k3) * h;
246 
247  return current_step + ((k1 + k2 * 2.f + k3 * 2.f + k4) * (1.f / 6.f));
248 }
249 
250 
252 {
253  decimal T = 0.0f;
254  do
255  {
256  temps.push_back(T);
257  T += h;
258  }
259  while (T <= TMax);
260 }
261 
262 vec3 Lancer::valideIntersection(const vec3& S, const vec3& R, const vec3* A, int& reflexion, const vec3& nExt_plan, const vec3& SR)
263 {
264 
265  /*
266  Calcule l'existence d'un trajet SR et d'une face convexe definie par un ensemble de 3 sommets Ai
267 
268  S : Coordonnees de la source. ATTENTION : la source ne doit pas se trouver dans le plan definit par A.
269  R : Coordonnees du recepteur
270  SR : vecteur Source-Recepteur
271 
272  A : Tableau contenant les 3 sommets de la face (tous les sommets doivent etre coplanaires)
273  Les sommets sont ordonnes ciculairement dans le sens trigonometrique (de sorte que la normale au plan soit la normale exterieure)
274 
275  nExt_plan : normale exterieure au plan considere.
276 
277  reflexion : variable test pour savoir si on a ou non trouve une intersection entre la droite SR et le plan A.
278  */
279 
280  vec3 I;
281  int test = 0;
282  reflexion = 2;
283  vec3 u = SR / SR.length(); // u : Vecteur directeur du trajet SR
284 
285  // Premier test : on calcule u.n
286  // Si le produit scalaire est positif ou nul, on ne rencontrera pas la face (on est respectivement en sens inverse ou parallele).
287 
288  double tmp = u * nExt_plan; //u.mult(nExt_plan);
289 
290  if (tmp >= 0)
291  {
292  test = 0;
293  reflexion = 0;
294  return I;
295  }
296 
297  // Deuxieme test : on regarde si le rayon va dans la direction du plan
298 
299  vec3 A1 = A[0];
300  vec3 A2 = A[1];
301  vec3 A3 = A[2];
302 
303  vec3 SA1(S, A1);
304  vec3 SA2(S, A2);
305  vec3 SA3(S, A3);
306 
307  double uu1 = u * SA1;
308  double uu2 = u * SA2;
309  double uu3 = u * SA3;
310 
311  if ((uu1 < 0) && (uu2 < 0) && (uu3 < 0))
312  {
313  test = 0;
314  reflexion = 0;
315  return I;
316  }
317 
318  // Troisieme test : on regarde si le produit scalaire entre u et chaque normale des 3 faces du tetraedre SA1A2A3 est negatif, c'est-a-dire si notre rayon entre dans le tetraedre.
319 
320  double u1 = u * (SA1 ^ SA2);
321  double u2 = u * (SA2 ^ SA3);
322  double u3 = u * (SA3 ^ SA1);
323 
324  if ((u1 >= 0) || (u2 >= 0) || (u3 >= 0))
325  {
326  test = 0;
327  reflexion = 0;
328  return I;
329  }
330 
331  test = 1; // on est dans la bonne direction
332 
333  // Dernier test : on regarde si on arrive sur la face
334 
335  double l = SA1 * nExt_plan;
336  l = l / tmp;
337 
338  // On calcule la longueur l du trajet SI ou I est le point d'impact sur la face
339  // si SR<SI alors le trajet ne rencontre pas la face, il s'arrete avant.
340 
341  if (test != 0)
342  {
343  if (l > SR.length())
344  {
345  // Le trajet ne rencontre pas la face, il s'arrete avant ...
346  reflexion = 0;
347  return I;
348  }
349  else
350  {
351  // Le point d'intersection a pour coordonnees S+l*u
352  reflexion = 1;
353  I = S + (u * (decimal)l);
354  }
355  }
356 
357  return I;
358 }
359 
360 void Lancer::intersection(const unsigned int& timer, RayCourb& current, Step& Y_t0, Step& Y_t1)
361 {
362  vec3 Imin(Y_t0.pos), n, nmin;
363  decimal Dmin = 0.;
364  int r, rmin;
365  bool premiere = 1; // variable boolenne pour savoir si on a deja rencontre un objet ou pas
366  int intersec = 2; // variable-test pour savoir s'il existe ou non une intersection
367  vec3 I; // point d'intersection
368 
369  // reflexions: on boucle sur tous les objets existants
370  for (r = 0; static_cast<unsigned int>(r) < _plan.size(); ++r)
371  {
372  // on determine les vecteurs directeurs u et v du plan plan[r]
373  vec3 u(_plan[r][0], _plan[r][1]);
374  vec3 v(_plan[r][0], _plan[r][2]);
375 
376  // on determine la normale exterieure n a ce plan
377  n = u ^ v;
378  n = n / n.length();
379 
380  // on calcule le point d'intersection entre le rayon et l'objet
381  I = valideIntersection(Y_t0.pos, Y_t1.pos, _plan[r], intersec, n, Y_t0.norm);
382 
383  if (intersec == 1) // si on a trouve un point d'intersection entre notre rayon et notre face r
384  {
385  decimal DI = sqrt((Y_t0.pos.x - I.x) * (Y_t0.pos.x - I.x) + (Y_t0.pos.y - I.y) * (Y_t0.pos.y - I.y) + (Y_t0.pos.z - I.z) * (Y_t0.pos.z - I.z));
386 
387  if (premiere == 0) // si ce n'est pas la premiere reflexion que l'on rencontre
388  {
389  if (DI < Dmin) // si cette condition est verifiee, alors le I trouve est plus proche que l'ancien, cad que c'est celui-ci que notre rayon va rencontrer
390  {
391  Imin = I;
392  Dmin = DI;
393  rmin = r;
394  nmin = n;
395  }
396  }
397  else
398  {
399  Imin = I;
400  Dmin = DI;
401  rmin = r;
402  nmin = n;
403 
404  premiere = 0; // on a une reflexion
405  }
406  }
407 
408  intersec = 2;
409  }
410 
411  if ((Imin.x != Y_t0.pos.x) || (Imin.y != Y_t0.pos.y) || (Imin.z != Y_t0.pos.z)) // si c'est le cas, cela signifie que notre rayon rencontre quelque chose
412  {
413  // on incremente le nombre de reflexions
414  current.nbReflex++;
415 
416  // on garde en memoire le pas de temps pour lequel il y a une reflexion
417  current.position.push_back(timer);
418 
419  // la "source" du rayon suivant est notre point d'intersection
420  Y_t1.pos = Imin;
421 
422  // on calcule le cosinus de l'angle forme par le rayon qui arrive et la normale n
423  decimal cos_angle = (-nmin) * (Y_t0.norm / Y_t0.norm.length());
424 
425  // enfin, on calcule la normale du rayon reflechi
426  Y_t1.norm = Y_t0.norm + nmin * Y_t0.norm.length() * cos_angle * 2.;
427 
428  current.rencontre.insert(pair<int, int>(timer, rmin));
429  }
430 }
431 
433 {
434  decimal result = 0;
435 
436  for (unsigned int ns = 0; ns < sources.size(); ++ns)
437  {
438  for (unsigned int nr = 0; nr < recepteurs.size(); ++nr)
439  {
440  result = max(result, sqrt((recepteurs[nr].x - sources[ns].x) * (recepteurs[nr].x - sources[ns].x) + (recepteurs[nr].y - sources[ns].y) * (recepteurs[nr].y - sources[ns].y) + (recepteurs[nr].z - sources[ns].z) * (recepteurs[nr].z - sources[ns].z)));
441  }
442  }
443 
444  return result * 1.2f; // multiplie par 1.2 pour esperer que le recepteur est dans la zone de deformation
445 }
446 
447 void Lancer::loadRayFile(vector<vec3>& tableau_norm)
448 {
449  ifstream para(ray_fileName.c_str()) ;
450 
451  // Lecture du nombre de rayons
452  para >> nbRay;
453 
454  for (unsigned int i = 0 ; i < nbRay ; i++)
455  {
456  // Recuperation des angles de depart
457  unsigned int numRay, nbEvent; // numero du rayon, nombre d'evenement sur le rayon
458  char c1, c2, c3;
459  decimal anglePhi, angleTheta;
460 
461  para >> numRay >> c1 >> anglePhi >> c2 >> angleTheta;
462  vec3 angles(anglePhi, angleTheta, 0);
463  tableau_norm.push_back(angles);
464 
465  // Boucle sur les evenements des rayons (ces valeurs ne sont pas utilisee - uniquement lecture
466  para >> nbEvent;
467  double x, y, z, bidon;
468 
469  for (unsigned int j = 0; j < nbEvent; j++)
470  {
471  para >> x >> c1 >> y >> c2 >> z >> c3 >> bidon;
472  }
473  }
474 
475  para.close();
476 }
477 
478 decimal angle_depart(const decimal& a, const decimal& c, const decimal& d, const decimal& h)
479 {
480  /*La fonction calcule l'angle avec lequel on doit lancer notre rayon pour qu'il parcoure, en ligne droite, une distance minimale d
481  a : gradient de celerite
482  c : celerite au sol
483  d : distance minimale a parcourir
484  h : hauteur de la source
485  */
486 
487  double a2 = a * a;
488  double d2 = d * d;
489  double c2 = c * c;
490  double h2 = h * h;
491 
492  return (decimal)(2 * atan((-4 * a * c * d + sqrt(16 * a2 * c2 * d2 + 4 * (a2 * d2 + a2 * h2 - 2 * c * h * a) * (a2 * d2 + a2 * h2 - 2 * c * h * a))) / (2 * (a2 * d2 + a2 * h2 - 2 * c * h * a))));
493 }
494 
495 
497 {
498  // on sauvegarde nos resultats dans un fichier .txt.
499  ostringstream nom_var;
500  nom_var << "MatRes_C" << dynamic_cast<meteoLin*>(_weather)->getGradC()
501  << "_V" << dynamic_cast<meteoLin*>(_weather)->getGradV()
502  << "_D" << dmax
503  << ".txt" << ends;
504 
505  ofstream fic_out(nom_var.str().c_str());
506 
507  for (unsigned int i = 0; i < MatRes.size(); i++)
508  {
509  for (unsigned int j = 0; j < nbRay; ++j)
510  {
511  for (unsigned int k = 0; k < MatRes[i][j].etapes.size(); ++k)
512  {
513  fic_out << MatRes[i][j].etapes[k].pos.x << " "
514  << MatRes[i][j].etapes[k].pos.y << " "
515  << MatRes[i][j].etapes[k].pos.z << endl;
516  }
517 
518  fic_out << endl << endl;
519  }
520  }
521 }
int nbReflex
Reflections number.
Definition: RayCourb.h:50
vector< vec3 * > _plan
List of objects defined by 3 points.
Definition: Lancer.h:148
virtual vec3 getSample()
Return the sample.
Definition: Sampler.h:65
Sampler * _sampler
Pointer to a ray generator.
Definition: Lancer.h:150
void setSize(const unsigned int taille)
Set the steps vector size.
Definition: RayCourb.h:43
meteo * _weather
Pointer to weather.
Definition: Lancer.h:149
void init_sampler()
Initialize ray generator.
Definition: Lancer.cpp:68
decimal TMax
Maximal propagation time.
Definition: Lancer.h:153
decimal finalAnglePhi
Final shot angle according phi.
Definition: Lancer.h:159
Describes analytical ray curve tracing.
Definition: Lancer.h:37
string ray_fileName
Filename of file containing angles of rays.
Definition: Lancer.h:164
decimal finalAngleTheta
Final shot angle according theta.
Definition: Lancer.h:157
~Lancer()
Destructor.
Definition: Lancer.cpp:63
unsigned int nbRay
Launched rays number.
Definition: Lancer.h:161
void createTemps()
Build the time vector (different times solved)
Definition: Lancer.cpp:251
decimal distance(const base_vec3 &a_vector) const
Compute the distance between two points pointed by *this and a_vector.
Definition: mathlib.h:230
STL namespace.
base_vec3< decimal > vec3
Definition: mathlib.h:269
void RemplirMat()
Fill the MatRes matrix containing the ray curves.
Definition: Lancer.cpp:202
decimal initialAngleTheta
Initial shot angle according theta.
Definition: Lancer.h:156
NxReal s
Definition: NxVec3.cpp:345
void save()
Save rays to a file.
Definition: Lancer.cpp:496
vector< RayCourb * > MatRes
Array containing the resulting rays for each source.
Definition: Lancer.h:167
vec3 norm
Step normal.
Definition: Step.h:48
decimal h
Discretization step.
Definition: Lancer.h:152
NxReal c
Definition: NxVec3.cpp:345
A Sampler class for longitudinal sampling.
Class to define linear gradient for wind and sound speed.
Definition: meteoLin.h:33
vec3 valideIntersection(const vec3 &S, const vec3 &R, const vec3 *A, int &reflexion, const vec3 &nExt_plan, const vec3 &SR)
Compute the intersection point between a plane and a line.
Definition: Lancer.cpp:262
3D vector Vector defined with 3 float numbers
Definition: mathlib.h:107
decimal dmax
Maximal distance traveled by the rays.
Definition: Lancer.h:155
vector< Step > etapes
Time steps vector.
Definition: RayCourb.h:49
base_t length(void) const
Definition: mathlib.h:167
A Sampler class for uniform spherical sampling.
void purgeMatRes()
Clear the memory of MatRes object.
Definition: Lancer.cpp:103
vector< vec3 > sources
Sources vector.
Definition: Lancer.h:146
void loadRayFile(vector< vec3 > &tableau_norm)
Read the file containing the starting angles of the rays.
Definition: Lancer.cpp:447
void intersection(const unsigned int &timer, RayCourb &current, Step &Y_t0, Step &Y_t1)
Definition: Lancer.cpp:360
Step compute_next_step(const Step &current_step)
Compute next step taking account of the weather.
Definition: Lancer.cpp:238
float decimal
Definition: mathlib.h:46
vector< int > position
List of the indices of points where reflection happens (time step number)
Definition: RayCourb.h:51
decimal angle_depart(const decimal &a, const decimal &c, const decimal &d, const decimal &h)
Compute the shooting angle ray in order to travel the given minimal distance.
Definition: Lancer.cpp:478
vec3 pos
Step position.
Definition: Step.h:47
decimal initialAnglePhi
Initial shot angle according phi.
Definition: Lancer.h:158
vector< decimal > temps
[0:h:TMax] Vector containing the different times solved
Definition: Lancer.h:154
map< int, int > rencontre
Tuple (time step, encountered face)
Definition: RayCourb.h:52
vector< vec3 > recepteurs
Receptors vector.
Definition: Lancer.h:147
decimal distance_max()
Compute and return the maximal distance between sources and receptors.
Definition: Lancer.cpp:432
Step EqRay(const Step &y0)
Function to define the eikonal equation.
Definition: Lancer.cpp:114
unsigned int _launchType
Launch type with 1:horizontal / 2:vertical / 3:spherical / 4:file.
Definition: Lancer.h:162
Another sampler class for uniform spherical sampling.
virtual void init()
Initialize the sample.
Definition: Sampler.h:69
Describe a step in the ray path.
Definition: Step.h:31
bool wantOutFile
True if an output file is wanted.
Definition: Lancer.h:163
A Sampler class for latitude sampling.
RayCourb RK4(const Step &y0)
Fourth order Runge-Kutta algorithm.
Definition: Lancer.cpp:150
Lancer()
Constructor.
Definition: Lancer.cpp:28
Class to describe a ray curve.
Definition: RayCourb.h:28