TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Loi_horaire.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Schema_Temps_base.h>
17#include <Probleme_base.h>
18#include <Loi_horaire.h>
19#include <TRUST_Ref.h>
20#include <SFichier.h>
21#include <sys/stat.h>
22#include <EChaine.h>
23#include <Param.h>
24
25Implemente_instanciable(Loi_horaire,"Loi_horaire",Objet_U);
26// XD loi_horaire objet_u loi_horaire BRACE to define the movement with a time-dependant law for the solid interface.
27
28Sortie& Loi_horaire::printOn(Sortie& os) const { return os; }
29
31{
32 EChaine x(dimension==3?"3 0. 0. 0.":"2 0. 0.");
33 x >> position_;
34 EChaine v(dimension==3?"3 0. 0. 0.":"2 0. 0.");
35 v >> vitesse_;
36 EChaine r(dimension==3?"9 1. 0. 0. 0. 1. 0. 0. 0. 1.":"4 1. 0. 0. 1.");
37 r >> rotation_;
38 EChaine drdt(dimension==3?"9 0. 0. 0. 0. 0. 0. 0. 0. 0.":"4 0. 0. 0. 0.");
39 drdt >> derivee_rotation_;
40
41 // Reading of dataset
42 Param param(que_suis_je());
43 param.ajouter("position",&position_); // XD attr position listchaine position OPT Vecteur position (default: zero
44 // XD_CONT vector of length `dimension`)
45 param.ajouter("vitesse",&vitesse_); // XD attr vitesse listchaine vitesse OPT Vecteur vitesse (default: zero
46 // XD_CONT vector of length `dimension`)
47 param.ajouter("rotation",&rotation_); // XD attr rotation listchaine rotation OPT Matrice de passage
48 param.ajouter("derivee_rotation",&derivee_rotation_); // XD attr derivee_rotation listchaine derivee_rotation OPT Derivee matrice de passage
49 param.ajouter("verification_derivee",&verification_derivee_); // XD attr verification_derivee entier verification_derivee OPT not_set
50 param.ajouter("impr",&impr_); // XD attr impr entier impr OPT Whether to print output
51 param.lire_avec_accolades_depuis(is);
52
53 // Verification of what was read: (why does le_nom() return nothing???
54 if (position_.valeurs().size_array()!=dimension)
55 {
56 Cerr << "The position vector of the schedule law " << le_nom() << " must have " << dimension << " components." << finl;
58 }
59 if (vitesse_.valeurs().size_array()!=dimension)
60 {
61 Cerr << "The velocity vector of the schedule law " << le_nom() << " must have " << dimension << " components." << finl;
63 }
64 if (rotation_.valeurs().size_array()!=dimension*dimension)
65 {
66 Cerr << "The matrix rotation of the schedule law " << le_nom() << " must be read" << finl;
67 Cerr << "as a vector of " << dimension*dimension << " components." << finl;
69 }
70 if (derivee_rotation_.valeurs().size_array()!=dimension*dimension)
71 {
72 Cerr << "The matrix derivee_rotation of the schedule law " << le_nom() << " must be read" << finl;
73 Cerr << "as a vector of " << dimension*dimension << " components." << finl;
75 }
76 return is;
77}
78
79inline void check(const DoubleTab& mat)
80{
81 // Champ_Fonc_t DoubleTab(1, nb_comp)
82 if (mat.dimension(0)!=1)
83 {
84 Cerr << "Problem in Loi_horaire::check" << finl;
85 Cerr << "Format of the array of values of Champ_Fonc_t" << finl;
86 Cerr << "Contact TRUST support." << finl;
88 }
89}
90
91// Matrix*Vector product stored in arrays
92inline void multiplie(const DoubleTab& matrice, ArrOfDouble& vecteur)
93{
94 check(matrice);
95 ArrOfDouble x(vecteur);
96 vecteur=0;
97 int dimension = vecteur.size_array();
98 for (int i=0; i<dimension; i++)
99 for (int j=0; j<dimension; j++)
100 vecteur[i] += matrice(0,i*dimension+j) * x[j];
101}
102
103// Product Inverse(Matrix)*Vector in arrays
104inline void inverse(const DoubleTab& mat, ArrOfDouble& x)
105{
106 check(mat);
107 int dimension = x.size_array();
108 if (dimension==2)
109 {
110 const double a=mat(0,0);
111 const double b=mat(0,1);
112 const double c=mat(0,2);
113 const double d=mat(0,3);
114 double det=a*d-b*c;
115 if (det==0)
116 {
117 Cerr << "Matrix of order 2 not invertible in Loi_horaire::inverse" << finl;
118 Cerr << mat << finl;
120 }
121 double y0=(d*x[0]-b*x[1])/det;
122 double y1=(-c*x[0]+a*x[1])/det;
123 x[0]=y0;
124 x[1]=y1;
125 }
126 else if (dimension==3)
127 {
128 const double a=mat(0,0);
129 const double b=mat(0,1);
130 const double c=mat(0,2);
131 const double d=mat(0,3);
132 const double e=mat(0,4);
133 const double f=mat(0,5);
134 const double g=mat(0,6);
135 const double h=mat(0,7);
136 const double i=mat(0,8);
137
138 double det=a*(e*i-f*h)
139 -b*(d*i-f*g)
140 +c*(d*h-e*g);
141 if (det==0)
142 {
143 Cerr << "Matrix of order 3 not invertible in Loi_horaire::inverse" << finl;
144 Cerr << mat << finl;
146 }
147 double y0=((e*i-f*h)*x[0]
148 +(c*h-b*i)*x[1]
149 +(b*f-c*e)*x[2])/det;
150 double y1=((f*g-d*i)*x[0]
151 +(a*i-c*g)*x[1]
152 +(c*d-a*f)*x[2])/det;
153 double y2=((d*h-e*g)*x[0]
154 +(b*g-a*h)*x[1]
155 +(a*e-b*d)*x[2])/det;
156 x[0]=y0;
157 x[1]=y1;
158 x[2]=y2;
159 }
160 else
161 {
162 Cerr << "Case not provided in Loi_horaire::inverse()" << finl;
164 }
165}
166
167/* Returns an array containing the position xM(t) of a point M at time t
168 as a function of time t0 and its position xM(t0) at time t0.
169 To do this, we use the following relations:
170 xM(t)=xG(t)+R(t)(xM(0)-xG(0))
171 xM(t0)=xG(t0)+R(t0)(xM(0)-xG(0))
172 We have:
173 xM(0)-xG(0)=R-1(t0)(xM(t0)-xG(t0))
174 Therefore:
175 xM(t) = xG(t)+R(t)R-1(t0)(xM(t0)-xG(t0))
176*/
177ArrOfDouble Loi_horaire::position(const double t, const double t0, const ArrOfDouble& xMt0)
178{
179 ArrOfDouble xMt(xMt0); // xM(t0)
180 position_.me_calculer(t0); // xG(t0)
181 xMt -= position_.valeurs(); // xM(t0)-xG(t0)
182 rotation_.me_calculer(t0); // R(t0)
183 inverse(rotation_.valeurs(),xMt); // R-1(t0)(xM(t0)-xG(t0))
184 rotation_.me_calculer(t); // R(t)
185 multiplie(rotation_.valeurs(),xMt); // R(t)R-1(t0)(xM(t0)-xG(t0))
186 position_.me_calculer(t); // xG(t)
187 xMt += position_.valeurs(); // xM(t) = xG(t)+R(t)R-1(t0)(xM(t0)-xG(t0))
188 return xMt;
189}
190
191/* Returns an array containing the velocity vM(t) of a point M at time t
192 as a function of its position xM(t) at time t. To know this velocity of point M,
193 we use the following relations:
194 xM(t)=xG(t)+R(t)(xM(0)-xG(0))
195 vM(t)=vG(t)+R'(t)(xM(0)-xG(0))
196 We have:
197 xM(0)-xG(0)=R-1(t)(xM(t)-xG(t))
198 Therefore:
199 vM(t) = vG(t)+R'(t)R-1(t)(xM(t)-xG(t))
200*/
201ArrOfDouble Loi_horaire::vitesse(const double t, const ArrOfDouble& xMt)
202{
203 ArrOfDouble vMt(xMt); // xM(t)
204 position_.me_calculer(t); // xG(t)
205 vMt -= position_.valeurs(); // xM(t)-xG(t)
206 rotation_.me_calculer(t); // R(t)
207 inverse(rotation_.valeurs(),vMt); // R-1(t)(xM(t)-xG(t))
208 derivee_rotation_.me_calculer(t); // R'(t)
209 multiplie(derivee_rotation_.valeurs(),vMt); // R'(t)R-1(t)(xM(t)-xG(t))
210 vitesse_.me_calculer(t); // vG(t)
211 vMt += vitesse_.valeurs(); // vM(t) = vG(t)+R'(t)R-1(t)(xM(t)-xG(t))
212 return vMt;
213}
214
215// Verification of consistency of velocity derivatives and derivee_rotation
216// with respect to position and rotation. We use a limited development of order 2
217// |f(t+dt)-f(t)-dt*f'(t)|=|0.5*f''(t)*dt*dt+O(dt*dt*dt)|>|10*f''(t)*dt*dt|
218// An error on expressions with zero second derivative will therefore not be detected...
219void Loi_horaire::verifier_derivee(const double t)
220{
221 if (verification_derivee_)
222 {
223 double dt=0.001*t;
224 DoubleVect err_t(position_.valeurs());
225 position_.me_calculer(t+dt); // xG(t+dt)
226 err_t=position_.valeurs(); // xG(t+dt)
227 position_.me_calculer(t); // xG(t)
228 err_t-=position_.valeurs(); // xG(t+dt)-xG(t)
229 vitesse_.me_calculer(t); // vG(t)
230 err_t.ajoute(-dt, vitesse_.valeurs()); // xG(t+dt)-xG(t)-dt*vG(t)
231 // Evaluation of a threshold with the second derivative xG'' i.e. vG'
232 ArrOfDouble seuil_t(position_.valeurs());
233 vitesse_.me_calculer(t+dt); // vG(t+dt)
234 seuil_t=vitesse_.valeurs();
235 vitesse_.me_calculer(t); // vG(t)
236 seuil_t-=vitesse_.valeurs();
237 seuil_t*=100*dt; // ~vG'(t)*dt*dt
238 int n=err_t.size_array();
239 for (int i=0; i<n; i++)
240 {
241 double seuil=std::fabs(seuil_t[i]);
242 if (!est_egal(seuil,0) && std::fabs(err_t(i))>seuil)
243 {
244 Cerr << "At time " << t << ", inconsistency in the schedule law " << le_nom() << finl;
245 Cerr << "The expression of the component " << i << " of velocity does not appear" << finl;
246 Cerr << "to be the time derivative of the position expression." << finl;
247 Cerr << "Verify the expressions of this schedule law in your data set." << finl;
248 Cerr << "If the expressions are correct after all, add the option 'verification_derivee 0'" << finl;
249 Cerr << "in the law to not to make this verification." << finl;
251 }
252 }
253 DoubleTab err_r(rotation_.valeurs());
254 rotation_.me_calculer(t+dt); // R(t+dt)
255 err_r=rotation_.valeurs(); // R(t+dt)
256 rotation_.me_calculer(t); // R(t)
257 err_r-=rotation_.valeurs(); // R(t+dt)-R(t)
258 derivee_rotation_.me_calculer(t); // R'(t)
259 err_r.ajoute(-dt, derivee_rotation_.valeurs()); // R(t+dt)-R(t)-dt*R'(t)
260 // Evaluation of a threshold with the second derivative of R i.e. R''
261 DoubleTab seuil_r(rotation_.valeurs());
262 derivee_rotation_.me_calculer(t+dt); // R'(t+dt)
263 seuil_r=derivee_rotation_.valeurs();
264 derivee_rotation_.me_calculer(t); // R'(t)
265 seuil_r-=derivee_rotation_.valeurs(); // R'(t+dt)-R'(t)
266 seuil_r*=100*dt; // ~R''(t)*dt*dt
267 int ni=err_r.dimension(0);
268 int nj=err_r.dimension(1);
269 for (int i=0; i<ni; i++)
270 for (int j=0; j<nj; j++)
271 {
272 double seuil=std::fabs(seuil_r(i,j));
273 if (!est_egal(seuil,0) && std::fabs(err_r(i,j))>seuil)
274 {
275 Cerr << "At time " << t << ", inconsistency in the schedule law " << le_nom() << finl;
276 Cerr << "The expression of the component " << i*ni+j << " of derivee_rotation does not appear" << finl;
277 Cerr << "to be the time derivative of the rotation expression." << finl;
278 Cerr << "Verify the expressions of this schedule law in your data set" << finl;
279 Cerr << "or add the option 'verification_derivee 0' in this law." << finl;
281 }
282 }
283 }
284}
285
286void Loi_horaire::imprimer(const Schema_Temps_base& sch, const ArrOfDouble& coord_barycentre)
287{
289 {
290 // File opening
291 Nom nom_fichier(nom_du_cas());
292 nom_fichier+="_loi_horaire_";
293 nom_fichier+=le_nom();
294 nom_fichier+=".out";
295 SFichier fic; // * os=nullptr;
296 struct stat f;
297 // Create the file on first printing with header or if the file does not exist
298 if (stat(nom_fichier,&f) || (sch.nb_impr()==1 && !sch.pb_base().reprise_effectuee()))
299 {
300 tester(sch);
301 fic.ouvrir(nom_fichier);
302 // Writing header
303 fic << "# (xG,yG,...):Position du centre de gravite dont le mouvement est defini par la loi horaire " << le_nom() << finl;
304 fic << "# (moy(xi),moy(yi),...):Position du barycentre des noeuds du maillage de l'interface." << finl;
305 fic << "# Les trajectoires de ces 2 points doivent etre proches." << finl;
306 fic << "# Pour visualiser dans gnuplot ces trajectoires, faire: " << finl;
307 if (dimension==3)
308 {
309 fic << "# set param;splot '" << nom_fichier << "' using 2:3:4 with lines,'" << nom_fichier << "' using 5:6:7 with points" << finl;
310 fic << "# Temps xG(t) yG(t) zG(t) moy(xi) moy(yi) moy(zi)" << finl;
311 }
312 else
313 {
314 fic << "# set param;plot '" << nom_fichier << "' using 2:3 with lines,'" << nom_fichier << "' using 4:5 with points" << finl;
315 fic << "# Temps xG(t) yG(t) moy(xi) moy(yi)" << finl;
316 }
317 }
318 else
319 fic.ouvrir(nom_fichier,ios::app);
320
321 fic.precision(sch.precision_impr());
322 fic.setf(ios::scientific);
323 // Writing t, xG(t), barycenter_coord
324 double t=sch.temps_courant();
325 fic << t;
326 position_.me_calculer(t);
327 for (int i=0; i<dimension; i++)
328 fic << " " << position_.valeurs()(0,i); // xG(t)
329 for (int i=0; i<dimension; i++)
330 fic << " " << coord_barycentre[i]; // Barycenter of interface nodes
331 fic << finl;
332 // File closing
333 fic.close();
334 }
335}
336
337// Various tests of the class
338void Loi_horaire::tester(const Schema_Temps_base& sch)
339{
340 // Matrix product and inversion test
341 for (int dim=2; dim<=3; dim++)
342 {
343 DoubleTab mat(1,dim*dim);
344 for (int i=0; i<dim; i++)
345 for (int j=0; j<dim; j++)
346 mat(0,i*dim+j)=(i>j?1+i+j:-2*j);
347 ArrOfDouble vect(dim);
348 for (int i=0; i<dim; i++)
349 vect[i]=i;
350 ArrOfDouble tmp(vect);
351 multiplie(mat,vect);
352 inverse(mat,vect);
353 for (int i=0; i<dim; i++)
354 if (!est_egal(tmp[i],vect[i]))
355 {
356 Cerr << "Loi_horaire::inverse is not validated for dim=" << dim << finl;
357 Cerr << "A=" << mat << finl;
358 Cerr << "x=" << tmp << finl;
359 Cerr << "Inv(A)Ax=" << vect << finl;
360 Cerr << "Contact TRUST support." << finl;
362 }
363 }
364 // Verification between tinit and tmax
365 double tinit=sch.temps_init();
366 double tmax=sch.temps_max();
367 // Test of derivatives:
368 int n=100;
369 for (int i=1; i<n; i++)
370 {
371 double temps=tinit+(tmax-tinit)*(i+1)/n;
372 //Cerr << "Verification a t=" << temps << finl;
373 verifier_derivee(temps);
374 }
375 // Test of position and velocity:
376 double t=0.5*(tinit+tmax);
377 double eps=1e-8;
378 double dt=eps*t;
379 ArrOfDouble pos(dimension);
380 pos[0]=dimension*2;
381 pos[1]=dimension*3;
382 if (dimension==3) pos[2]=-dimension;
383 // Verification that position(t,t,pos)=pos
384 ArrOfDouble tmp(position(t,t,pos));
385 for (int i=0; i<dimension; i++)
386 if (!est_egal(tmp[i],pos[i]))
387 {
388 Cerr << "Loi_horaire::position is not validated for pos=position(t,t,pos):" << finl;
389 Cerr << pos << finl;
390 Cerr << tmp << finl;
391 Cerr << "Contact TRUST support." << finl;
393 }
394 // Verification that velocity(t,pos)~(position(t+dt,t,pos)-pos)/dt;
395 tmp=position(t+dt,t,pos);
396 tmp-=pos;
397 tmp/=dt;
398 ArrOfDouble vit(vitesse(t,pos));
399 ArrOfDouble relative_error(vit);
400 relative_error-=tmp;
401 relative_error/=(norme_array(tmp)!=0?norme_array(tmp):1);
402 for (int i=0; i<dimension; i++)
403 if (!est_egal(relative_error[i],0,0.001))
404 {
405 Cerr << "Loi_horaire::position is not validated for velocity(t,pos):" << finl;
406 Cerr << "t=" << t << finl;
407 Cerr << "dt=" << dt << finl;
408 Cerr << "vit=" << vit << finl;
409 Cerr << "tmp=" << tmp << finl;
410 Cerr << "relative_error=" << relative_error << finl;
411 Cerr << "Contact TRUST support." << finl;
413 }
414 Cerr << "Loi_horaire::tester() OK" << finl;
415}
416
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
ArrOfDouble vitesse(const double t, const ArrOfDouble &position_a_t)
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Loi_horaire.h:39
void imprimer(const Schema_Temps_base &, const ArrOfDouble &)
ArrOfDouble position(const double t, const double t0, const ArrOfDouble &position_a_t0)
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
Base class for TRUST objects (Objet_U).
Definition Objet_U.h:68
static int dimension
Definition Objet_U.h:94
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
bool & reprise_effectuee()
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
class Schema_Temps_base
int nb_impr() const
Returns the number of outputs performed.
double temps_courant() const
Returns the current time.
double temps_max() const
Returns a reference to the maximum time.
Probleme_base & pb_base()
double temps_init() const
Returns the initial time.
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
void precision(int pre) override
void setf(IOS_FORMAT code) override
Base class for output streams.
Definition Sortie.h:52
_SIZE_ size_array() const
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133