LORENE
evolution.C
1 /*
2  * Methods of template class Evolution
3  *
4  * (see file evolution.h for documentation).
5  *
6  */
7 
8 /*
9  * Copyright (c) 2004 Eric Gourgoulhon & Jerome Novak
10  *
11  * This file is part of LORENE.
12  *
13  * LORENE is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2
15  * as published by the Free Software Foundation.
16  *
17  * LORENE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with LORENE; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25  *
26  */
27 
28 /*
29  * $Id: evolution.C,v 1.21 2026/02/26 09:51:02 j_novak Exp $
30  * $Log: evolution.C,v $
31  * Revision 1.21 2026/02/26 09:51:02 j_novak
32  * Corrected an assert that was too strict for the interpolation.
33  *
34  * Revision 1.20 2025/03/18 14:16:32 j_novak
35  * Corrected a missing include
36  *
37  * Revision 1.19 2025/03/18 14:06:02 j_novak
38  * Added extrapolation method (constant,linear or parabolic) in the Evolution template class.
39  *
40  * Revision 1.18 2014/10/13 08:52:38 j_novak
41  * Lorene classes and functions now belong to the namespace Lorene.
42  *
43  * Revision 1.17 2014/03/27 16:59:41 j_novak
44  * Added methods next_position(int) and previous_position(int). Changed (corrected + simplified) the interpolation method.
45  *
46  * Revision 1.16 2013/07/19 15:50:24 j_novak
47  * Implementation of the interpolation function for Evolution, with order=0, 1 or 2.
48  *
49  * Revision 1.15 2008/09/19 13:24:29 j_novak
50  * Added the third-order scheme for the time derivativre computation.
51  *
52  * Revision 1.14 2004/05/14 08:51:01 p_grandclement
53  * *** empty log message ***
54  *
55  * Revision 1.13 2004/05/14 08:41:05 e_gourgoulhon
56  * Added declaration "class Tbl ;" before the declarations of
57  * write_formatted.
58  *
59  * Revision 1.12 2004/05/13 21:30:32 e_gourgoulhon
60  * Use of function write_formatted in method save( ).
61  *
62  * Revision 1.11 2004/05/11 20:12:49 e_gourgoulhon
63  * Added methods j_min, j_max and save.
64  *
65  * Revision 1.10 2004/05/03 15:23:22 e_gourgoulhon
66  * Method downdate: changed the order of conditions (pos_jtop>=0)
67  * and (val[pos_jtop] == 0x0) in the while(...) test.
68  *
69  * Revision 1.9 2004/03/31 20:24:04 e_gourgoulhon
70  * Method time_derive: result object created by the copy constructor of
71  * class TyT, since the arithmetics may not return an object of exactly
72  * class TyT.
73  *
74  * Revision 1.8 2004/03/26 13:31:09 j_novak
75  * Definition of the macro UNDEF_STEP for non-defined time-steps.
76  * Changes in the way the time derivative is calculated.
77  *
78  * Revision 1.7 2004/03/26 08:22:13 e_gourgoulhon
79  * *** Full reorganization of class Evolution ***
80  * Introduction of the notion of absoluteuniversal time steps,
81  * stored in the new array 'step'.
82  * The new function position(int j) makes a correspondence
83  * between a universal time step j and the position in the
84  * arrays step, the_time and val.
85  * Only method update is now virtual.
86  * Methods operator[], position, is_known, downdate belong to
87  * the base class.
88  *
89  * Revision 1.6 2004/03/24 14:55:47 e_gourgoulhon
90  * Added method last_value().
91  *
92  * Revision 1.5 2004/03/23 14:50:41 e_gourgoulhon
93  * Added methods is_updated, downdate, get_jlast, get_size,
94  * as well as constructors without any initial value.
95  * Formatted documentation for Doxygen.
96  *
97  * Revision 1.4 2004/03/06 21:13:15 e_gourgoulhon
98  * Added time derivation (method time_derive).
99  *
100  * Revision 1.3 2004/02/17 22:13:34 e_gourgoulhon
101  * Suppressed declaration of global char[] evolution_C = ...
102  *
103  * Revision 1.2 2004/02/15 21:55:33 e_gourgoulhon
104  * Introduced derived classes Evolution_full and Evolution_std.
105  * Evolution is now an abstract base class.
106  *
107  * Revision 1.1 2004/02/13 15:53:20 e_gourgoulhon
108  * New (template) class for time evolution.
109  *
110  *
111  * $Header: /cvsroot/Lorene/C++/Include/Template/evolution.C,v 1.21 2026/02/26 09:51:02 j_novak Exp $
112  *
113  */
114 
115 // C headers
116 #include <cassert>
117 
118 // C++ headers
119 #include "headcpp.h"
120 
121 namespace Lorene {
122 class Tbl ;
123 
124 void write_formatted(const double&, ostream& ) ;
125 void write_formatted(const Tbl&, ostream& ) ;
126 
127 
128  //-------------------------//
129  // Constructors //
130  //-------------------------//
131 
132 
133 template<typename TyT>
134 Evolution<TyT>::Evolution(const TyT& initial_value, int initial_step,
135  double initial_time, int size_i)
136  : size(size_i),
137  pos_jtop(0) {
138 
139  step = new int[size] ;
140  step[0] = initial_step ;
141  for (int j=1; j<size; j++) {
142  step[j] = UNDEF_STEP ;
143  }
144 
145  the_time = new double[size] ;
146  the_time[0] = initial_time ;
147  for (int j=1; j<size; j++) {
148  the_time[j] = -1e20 ;
149  }
150 
151  val = new TyT*[size] ;
152  val[0] = new TyT(initial_value) ;
153  for (int j=1; j<size; j++) {
154  val[j] = 0x0 ;
155  }
156 
157 }
158 
159 
160 template<typename TyT>
162  : size(size_i),
163  pos_jtop(-1) {
164 
165  step = new int[size] ;
166  for (int j=0; j<size; j++) {
167  step[j] = UNDEF_STEP ;
168  }
169 
170  the_time = new double[size] ;
171  for (int j=0; j<size; j++) {
172  the_time[j] = -1e20 ;
173  }
174 
175  val = new TyT*[size] ;
176  for (int j=0; j<size; j++) {
177  val[j] = 0x0 ;
178  }
179 
180 }
181 
182 
183 
184 template<typename TyT>
186  : size(evo.size),
187  pos_jtop(evo.pos_jtop) {
188 
189  step = new int[size] ;
190  for (int j=0; j<size; j++) {
191  step[j] = evo.step[j] ;
192  }
193 
194  the_time = new double[size] ;
195  for (int j=0; j<size; j++) {
196  the_time[j] = evo.the_time[j] ;
197  }
198 
199  val = new TyT*[size] ;
200  for (int j=0; j<size; j++) {
201  if (evo.val[j] != 0x0) {
202  val[j] = new TyT( *(evo.val[j]) ) ;
203  }
204  else {
205  val[j] = 0x0 ;
206  }
207  }
208 
209 
210 }
211 
212 
213 
214 
215  //-----------------------//
216  // Destructor //
217  //-----------------------//
218 
219 
220 template<typename TyT>
222 
223  delete [] step ;
224  delete [] the_time ;
225 
226  for (int j=0; j<size; j++) {
227  if (val[j] != 0x0) delete val[j] ;
228  }
229 
230  delete [] val ;
231 
232 }
233 
234 
235 
236  //-----------------------//
237  // Mutators //
238  //-----------------------//
239 
240 
241 template<typename TyT>
243 
244  cerr << "void Evolution<TyT>::operator= : not implemented yet ! \n" ;
245  abort() ;
246 
247 }
248 
249 
250 template<typename TyT>
252 
253  if ( !(is_known(j)) ) return ; // a never updated step cannot
254  // be downdated
255 
256  int pos = position(j) ;
257 
258  assert( val[pos] != 0x0) ;
259 
260  delete val[pos] ;
261  val[pos] = 0x0 ;
262  step[pos] = UNDEF_STEP ;
263  the_time[pos] = -1e20 ;
264 
265  if (pos == pos_jtop) { // pos_jtop must be decreased
266  pos_jtop-- ;
267  while ( (pos_jtop>=0) && (val[pos_jtop] == 0x0) ) pos_jtop-- ;
268  }
269 
270 }
271 
272 
273 
274 
275  //------------//
276  // Accessors //
277  //------------//
278 
279 template<typename TyT>
280 int Evolution<TyT>::position(int j) const {
281 
282  assert(pos_jtop >= 0) ;
283  int jmax = step[pos_jtop] ;
284 
285  if (j == jmax) return pos_jtop ; // for efficiency purpose
286 
287  int pos = - 1 ;
288 
289  if ( (j>=step[0]) && (j<jmax) ) {
290 
291  for (int i=pos_jtop-1; i>=0; i--) { // cas i=pos_jtop treated above
292  if (step[i] == j) {
293  pos = i ;
294  break ;
295  }
296  }
297  }
298 
299  if (pos == -1) {
300  cerr << "Evolution<TyT>::position: time step j = " <<
301  j << " not found !" << endl ;
302  abort() ;
303  }
304 
305  return pos ;
306 }
307 
308 template<typename TyT>
310 
311  assert( (j>=0) && (j<=pos_jtop) ) ;
312  assert( step[j] != UNDEF_STEP ) ;
313 
314  int n_pos = -1 ;
315 
316  while ( (n_pos == -1) && ( j < pos_jtop ) ) {
317 
318  j++ ;
319  if (step[j] != UNDEF_STEP) n_pos = j ;
320  }
321  return n_pos ;
322 }
323 
324 template<typename TyT>
326 
327  assert( (j>=0) && (j<=pos_jtop) ) ;
328  assert( step[j] != UNDEF_STEP ) ;
329 
330  int n_pos = -1 ;
331 
332  while ( (n_pos == -1) && ( j > 0 ) ) {
333 
334  j-- ;
335  if (step[j] != UNDEF_STEP) n_pos = j ;
336  }
337  return n_pos ;
338 }
339 
340 
341 template<typename TyT>
342 bool Evolution<TyT>::is_known(int j) const {
343 
344  if (pos_jtop == -1) return false ;
345 
346  assert(pos_jtop >= 0) ;
347 
348  int jmax = step[pos_jtop] ;
349 
350  if (j == jmax) {
351  return ( val[pos_jtop] != 0x0 ) ;
352  }
353 
354  if ( (j>=step[0]) && (j<jmax) ) {
355 
356  for (int i=pos_jtop-1; i>=0; i--) { // cas i=pos_jtop treated above
357 
358  if (step[i] == j) return ( val[i] != 0x0 ) ;
359  }
360  }
361 
362  return false ;
363 }
364 
365 
366 template<typename TyT>
367 const TyT& Evolution<TyT>::operator[](int j) const {
368 
369  TyT* pval = val[position(j)] ;
370  assert(pval != 0x0) ;
371  return *pval ;
372 
373 }
374 
375 
376 template<typename TyT>
377 TyT Evolution<TyT>::operator()(double t, int order) const {
378 
379  int imin = position( j_min() ) ;
380 
381  if ( ( t < the_time[ imin ] ) || ( t > the_time[pos_jtop] ) ) {
382  cerr << "Evolution<TyT>::operator()(double t, int order) : \n"
383  << "Requested time outside stored range!" << endl ;
384  abort() ;
385  }
386  assert ( order <= 2 ) ;
387  assert ( pos_jtop >= order ) ;
388 
389  int j0 = imin ;
390 
391  while ((the_time[j0] < t) && ( j0 < pos_jtop )) {
392  j0 = next_position(j0) ;
393  assert( j0 != -1 ) ;
394  }
395 
396  switch (order) {
397 
398  case 0: {
399 
400  return (*val[j0]) ;
401 
402  break ;
403  }
404 
405  case 1: {
406 
407  int j1 = ( (j0 > imin) ? previous_position(j0) : next_position(j0) ) ;
408  assert( j1 != -1) ;
409 
410  double x0 = the_time[j1] - t ;
411  double x1 = the_time[j0] - t ;
412  double dx = the_time[j0] - the_time[j1] ;
413 
414  double a0 = x1 / dx ;
415  double a1 = x0 / dx ;
416 
417  return (a0*(*val[j0]) - a1*(*val[j1])) ;
418 
419  break ;
420  }
421 
422  case 2: {
423 
424  int j1 = ( (j0 == imin) ? next_position(j0) : previous_position(j0) ) ;
425  assert( j1 != -1) ;
426 
427  int j2 = -1 ;
428  if (j0 == imin)
429  j2 = next_position(j1) ;
430  else {
431  if (j1 == imin)
432  j2 = next_position(j0) ;
433  else
434  j2 = previous_position(j1) ;
435  }
436  assert (j2 != -1 ) ;
437 
438  double x0 = t - the_time[j0] ;
439  double x1 = t - the_time[j1] ;
440  double dx = the_time[j0] - the_time[j1] ;
441 
442  double x2 = t - the_time[j2] ;
443 
444  double dx0 = the_time[j1] - the_time[j2] ;
445  double dx1 = the_time[j0] - the_time[j2] ;
446  double dx2 = dx ;
447 
448  double a0 = ( x2*x1 ) / ( dx2*dx1 ) ;
449  double a1 = ( x0*x2 ) / ( dx0*dx2 ) ;
450  double a2 = ( x0*x1 ) / ( dx0*dx1 ) ;
451 
452  return ( a0*(*val[j0]) - a1*(*val[j1]) + a2*(*val[j2]) ) ;
453 
454  break ;
455  }
456 
457  default: {
458  cerr << " Evolution<TyT>::operator()(double t, int order) : \n" << endl ;
459  cerr << " The case order = " << order << " is not implemented!" << endl ;
460  abort() ;
461  break ;
462  }
463  }
464 
465  return *val[j0] ;
466 
467 }
468 
469 template<typename TyT>
470 TyT Evolution<TyT>::extrapolate(double t, int order) const {
471 
472  if ( t < the_time[pos_jtop] ) {
473  cerr << "Evolution<TyT>::extrapolate(double t, int order) : \n"
474  << "Requested time is inside stored range..." << endl ;
475  abort() ;
476  }
477  assert ( pos_jtop >= order ) ;
478 
479  switch (order) {
480 
481  case 0: {
482  return *val[pos_jtop];
483  break ;
484  }
485 
486  case 1: {
487  int j0 = UNDEF_STEP ;
488  for (int i=pos_jtop-1; i>=0; i--) {
489  if (step[i] != UNDEF_STEP) {
490  j0 = i ;
491  break ;
492  }
493  }
494  assert(j0 != UNDEF_STEP) ;
495  int j1 = pos_jtop ;
496 
497  double fac = (t - the_time[j0]) / (the_time[j1] - the_time[j0]) ;
498  return fac*(*val[j1]) + (1. - fac)*(*val[j0]) ;
499  break ;
500  }
501 
502  case 2: {
503  int j2 = pos_jtop ;
504  int j1 = UNDEF_STEP ;
505  for (int i=j2-1; i>=0; i--) {
506  if (step[i] != UNDEF_STEP) {
507  j1 = i ;
508  break ;
509  }
510  }
511  assert(j1 != UNDEF_STEP) ;
512  int j0 = UNDEF_STEP ;
513  for (int i=j1-1; i>=0; i--) {
514  if (step[i] != UNDEF_STEP) {
515  j0 = i ;
516  break ;
517  }
518  }
519  assert(j0 != UNDEF_STEP) ;
520 
521  double t0 = the_time[j0] ;
522  double t1 = the_time[j1] ;
523  double t2 = the_time[j2] ;
524  double t01 = t0 - t1 ;
525  double t02 = t0 - t2 ;
526  double t12 = t1 - t2 ;
527 
528  return ((t - t1)*(t - t2)/(t01*t02))*(*val[j0])
529  - ((t - t0)*(t - t2)/(t01*t12))*(*val[j1])
530  + ((t - t0)*(t - t1)/(t02*t12))*(*val[j2]) ;
531  break ;
532  }
533 
534  default: {
535  cerr << " Evolution<TyT>::extrapolate(double t, int order) : \n" << endl ;
536  cerr << " The case order = " << order << " is not implemented!" << endl ;
537  abort() ;
538  break ;
539  }
540  }
541 
542  return *val[pos_jtop] ;
543 }
544 
545 
546 
547 template<typename TyT>
549 
550  int resu = UNDEF_STEP ;
551  for (int i=0; i<=pos_jtop; i++) {
552  if (step[i] != UNDEF_STEP) {
553  resu = step[i] ;
554  break ;
555  }
556  }
557 
558  if (resu == UNDEF_STEP) {
559  cerr << "Evolution<TyT>::j_min() : no valid time step found !" << endl ;
560  abort() ;
561  }
562 
563  return resu ;
564 }
565 
566 template<typename TyT>
568 
569  if (pos_jtop == -1) {
570  cerr << "Evolution<TyT>::j_max() : no valid time step found !" << endl ;
571  abort() ;
572  }
573 
574  assert(pos_jtop >=0) ;
575  int jmax = step[pos_jtop] ;
576  assert(jmax != UNDEF_STEP) ;
577  return jmax ;
578 }
579 
580 
581 
582 
583 
584  //-----------------------//
585  // Time derivative //
586  //-----------------------//
587 
588 template<typename TyT>
589 TyT Evolution<TyT>::time_derive(int j, int n) const {
590 
591  if (n == 0) {
592  TyT resu ( operator[](j) ) ;
593  resu = 0 * resu ;
594 
595  return resu ;
596 
597  }
598 
599  else {
600 
601  int pos = position(j) ;
602  assert ( pos > 0 ) ;
603  assert ( step[pos-1] != UNDEF_STEP ) ;
604 
605  switch (n) {
606 
607  case 1 : {
608 
609  double dt = the_time[pos] - the_time[pos-1] ;
610 
611  return ( (*val[pos]) - (*val[pos-1]) ) / dt ;
612  break ;
613  }
614 
615  case 2 : {
616 
617  assert ( pos > 1 ) ;
618  assert ( step[pos-2] != UNDEF_STEP ) ;
619  double dt = the_time[pos] - the_time[pos-1] ;
620 #ifndef NDEBUG
621  double dt2 = the_time[pos-1] - the_time[pos-2] ;
622  if (fabs(dt2 -dt) > 1.e-13) {
623  cerr <<
624  "Evolution<TyT>::time_derive: the current version is"
625  << " valid only for \n"
626  << " a constant time step !" << endl ;
627  abort() ;
628  }
629 #endif
630  return ( 1.5* (*val[pos]) - 2.* (*val[pos-1]) + 0.5* (*val[pos-2]) ) / dt ;
631  break ;
632  }
633 
634  case 3 : {
635 
636  assert ( pos > 2 ) ;
637  assert ( step[pos-2] != UNDEF_STEP ) ;
638  assert ( step[pos-3] != UNDEF_STEP ) ;
639  double dt = the_time[pos] - the_time[pos-1] ;
640 #ifndef NDEBUG
641  double dt2 = the_time[pos-1] - the_time[pos-2] ;
642  double dt3 = the_time[pos-2] - the_time[pos-3] ;
643  if ((fabs(dt2 -dt) > 1.e-13)||(fabs(dt3 -dt2) > 1.e-13)) {
644  cerr <<
645  "Evolution<TyT>::time_derive: the current version is valid only for \n"
646  << " a constant time step !" << endl ;
647  abort() ;
648  }
649 #endif
650  return ( 11.*(*val[pos]) - 18.*(*val[pos-1]) + 9.*(*val[pos-2])
651  - 2.*(*val[pos-3])) / (6.*dt) ;
652  break ;
653  }
654  default : {
655  cerr << "Evolution<TyT>::time_derive: the case n = " << n
656  << " is not implemented !" << endl ;
657  abort() ;
658  break ;
659  }
660  }
661 
662  }
663  return operator[](j) ;
664 }
665 
666 
667 
668  //-----------------------//
669  // Outputs //
670  //-----------------------//
671 
672 
673 template<typename TyT>
674 void Evolution<TyT>::save(const char* filename) const {
675 
676  ofstream fich(filename) ;
677 
678  time_t temps = time(0x0) ;
679 
680  fich << "# " << filename << " " << ctime(&temps) ;
681  fich << "# " << size << " size" << '\n' ;
682  fich << "# " << pos_jtop << " pos_jtop" << '\n' ;
683  fich << "# t value... \n" ;
684 
685  fich.precision(14) ;
686  fich.setf(ios::scientific) ;
687  fich.width(20) ;
688  for (int i=0; i<=pos_jtop; i++) {
689  if (step[i] != UNDEF_STEP) {
690  fich << the_time[i] ; fich.width(23) ;
691  assert(val[i] != 0x0) ;
692  write_formatted(*(val[i]), fich) ;
693  fich << '\n' ;
694  }
695  }
696 
697  fich.close() ;
698 }
699 
700 
701 
702 
703 
704 
705 
706 
707 
708 
709 
710 
711 
712 
713 
714 
715 
716 
717 }
Lorene prototypes.
Definition: app_hor.h:67
TyT ** val
Array of pointers onto the values (size = size).
Definition: evolution.h:140
Evolution(const TyT &initial_value, int initial_j, double initial_time, int initial_size)
Constructor from some initial value.
Definition: evolution.C:134
int * step
Array of time step indices (size = size).
Definition: evolution.h:134
double * the_time
Array of values of t at the various time steps (size = size).
Definition: evolution.h:137
Time evolution.
Definition: evolution.h:123