# include # include # include # include # include # include # include using namespace std; # include "stiff_exact.hpp" int main ( ); void stiff_value ( ); void stiff_euler_test ( int n ); void stiff_euler ( int n, double t[], double y[] ); void plot2 ( int n1, double t1[], double y1[], int n2, double t2[], double y2[], string header, string title ); void plot4 ( int n1, double t1[], double y1[], int n2, double t2[], double y2[], int n3, double t3[], double y3[], int n4, double t4[], double y4[], string header, string title ); double *r8vec_linspace_new ( int n, double a, double b ); void timestamp ( ); //****************************************************************************80 int main ( ) //****************************************************************************80 // // Purpose: // // stiff_exact_test() tests stiff_exact(). // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 23 June 2025 // // Author: // // John Burkardt // { int n; timestamp ( ); cout << "\n"; cout << "stiff_exact_test():\n"; cout << " C++ version\n"; cout << " Test stiff_exact(), which evaluates exact solutions\n"; cout << " of a stiff ODE.\n"; stiff_value ( ); n = 27; stiff_euler_test ( n ); // // Terminate. // cout << "\n"; cout << "stiff_exact_test():\n"; cout << " Normal end of execution.\n"; timestamp ( ); return 0; } //****************************************************************************80 void stiff_value ( ) //****************************************************************************80 // // Purpose: // // stiff_value() evaluates the exact solution for various initial conditions. // // Discussion: // // y' = lambda * ( cos(t-t0) - y ) // y(t0) = y0 // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 23 June 2025 // // Author: // // John Burkardt // { double lambda; int nt; double t0; double *t1; double *t2; double *t3; double *t4; double tstop; double y0; double *y1; double *y2; double *y3; double *y4; nt = 101; // // Set initial parameter values. // lambda = 50.0; t0 = 0.0; y0 = 0.0; tstop = 1.0; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); // // Report initial parameter values. // cout << "\n"; cout << " Initial parameters:\n"; cout << " lambda = " << lambda << "\n"; cout << " t0 = " << t0 << "\n"; cout << " y0 = " << y0 << "\n"; cout << " tstop = " << tstop << "\n"; // // Default with t0 = 0, y0 = 0. // t0 = 0.0; y0 = 0.0; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); t1 = r8vec_linspace_new ( nt, t0, tstop ); y1 = stiff_exact ( nt, t1 ); // // Try t0=0, y0=0.9. // t0 = 0.0; y0 = 0.9; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); t2 = r8vec_linspace_new ( nt, t0, tstop ); y2 = stiff_exact ( nt, t2 ); // // Try t0=0, y0=1.5. // t0 = 0.0; y0 = 1.5; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); t3 = r8vec_linspace_new ( nt, t0, tstop ); y3 = stiff_exact ( nt, t3 ); // // t0 = 0.25, y0 = 0.5 // t0 = 0.25; y0 = 0.5; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); t4 = r8vec_linspace_new ( nt, t0, tstop ); y4 = stiff_exact ( nt, t4 ); // // Plot them. // plot4 ( nt, t1, y1, nt, t2, y2, nt, t3, y3, nt, t4, y4, "stiff_value", "Stiff ODE exact solutions" ); // // Free memory. // delete [] t1; delete [] t2; delete [] t3; delete [] t4; delete [] y1; delete [] y2; delete [] y3; delete [] y4; return; } //****************************************************************************80 void stiff_euler_test ( int n ) //****************************************************************************80 // // Purpose: // // stiff_euler_test() tests stiff_euler(). // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 23 June 2025 // // Author: // // John Burkardt // // Input: // // int N: the number of steps to take. // { double lambda; const int n2 = 101; double t0; double *t1; double *t2; double tstop; double y0; double *y1; double *y2; cout << "\n"; cout << "stiff_euler_test():\n"; cout << " Solve stiff ODE using the Euler method.\n"; // // Set initial parameter values. // lambda = 50; t0 = 0.0; y0 = 0.0; tstop = 1.0; stiff_parameters ( &lambda, &t0, &y0, &tstop, NULL, NULL, NULL, NULL ); cout << "\n"; cout << " Parameters:\n"; cout << " lambda = " << lambda << "\n"; cout << " t0 = " << t0 << "\n"; cout << " y0 = " << y0 << "\n"; cout << " tstop = " << tstop << "\n"; stiff_parameters ( NULL, NULL, NULL, NULL, NULL, &t0, NULL, &tstop ); t1 = new double[n+1]; y1 = new double[n+1]; stiff_euler ( n, t1, y1 ); t2 = r8vec_linspace_new ( n2, t0, tstop ); y2 = stiff_exact ( n2, t2 ); plot2 ( n+1, t1, y1, n2, t2, y2, "stiff_euler", "Stiff ODE solved using euler method" ); delete [] t1; delete [] t2; delete [] y1; delete [] y2; return; } //****************************************************************************80 void stiff_euler ( int n, double t[], double y[] ) //****************************************************************************80 // // Purpose: // // stiff_euler() uses the Euler method on the stiff equation. // // Discussion: // // y' = lambda * ( cos(t-t0) - y ) // y(t0) = y0 // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 20 June 2025 // // Author: // // John Burkardt // // Input: // // int N: the number of steps to take. // // Output: // // double T[N+1], Y[N+1]: the times and estimated solutions. // { double dt; int i; double lambda; double t0; double tstop; double y0; stiff_parameters ( NULL, NULL, NULL, NULL, &lambda, &t0, &y0, &tstop ); dt = ( tstop - t0 ) / ( double ) ( n ); t[0] = t0; y[0] = y0; for ( i = 0; i < n; i++ ) { t[i+1] = t[i] + dt; y[i+1] = y[i] + dt * lambda * ( cos ( t[i] - t0 ) - y[i] ); } return; } //****************************************************************************80 void plot2 ( int n1, double t1[], double y1[], int n2, double t2[], double y2[], string header, string title ) //****************************************************************************80 // // Purpose: // // plot2() plots two curves together. // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 29 April 2020 // // Author: // // John Burkardt // // Input: // // int N1: the size of the first data set. // // double T1(N1), Y1(N1), the first dataset. // // int N2: the size of the second data set. // // double T2(N2), Y2(N2), the secod dataset. // // string HEADER: an identifier for the data. // // string TITLE: a title to appear in the plot. // { string command_filename; ofstream command; string data1_filename; string data2_filename; ofstream data; int i; // // Create the data files. // data1_filename = header + "_data1.txt"; data.open ( data1_filename.c_str ( ) ); for ( i = 0; i < n1; i++ ) { data << " " << t1[i] << " " << y1[i] << "\n"; } data.close ( ); data2_filename = header + "_data2.txt"; data.open ( data2_filename.c_str ( ) ); for ( i = 0; i < n2; i++ ) { data << " " << t2[i] << " " << y2[i] << "\n"; } data.close ( ); cout << "\n"; cout << " plot2: data stored in '" << data1_filename << "' and '" << data2_filename << "'\n"; // // Create the command file. // command_filename = header + "_commands.txt"; command.open ( command_filename.c_str ( ) ); command << "# " << command_filename << "\n"; command << "#\n"; command << "# Usage:\n"; command << "# gnuplot < " << command_filename << "\n"; command << "#\n"; command << "set term png\n"; command << "set output '" << header << ".png'\n"; command << "set xlabel '<-- T -->'\n"; command << "set ylabel '<-- Y(T) -->'\n"; command << "set title '" << title << "'\n"; command << "set grid\n"; command << "set style data lines\n"; command << "plot '" << data1_filename << "' using 1:2 with lines lw 3 lt rgb 'red',\\\n"; command << " '" << data2_filename << "' using 1:2 with lines lw 3 lt rgb 'blue'\n"; command << "quit\n"; command.close ( ); cout << " plot2: plot commands stored in '" << command_filename << "'.\n"; return; } //****************************************************************************80 void plot4 ( int n1, double t1[], double y1[], int n2, double t2[], double y2[], int n3, double t3[], double y3[], int n4, double t4[], double y4[], string header, string title ) //****************************************************************************80 // // Purpose: // // plot4() plots four curves together. // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 23 June 2025 // // Author: // // John Burkardt // // Input: // // int N1: the size of the first data set. // // double T1(N1), Y1(N1), the first dataset. // // int N2: the size of the second data set. // // double T2(N2), Y2(N2), the second dataset. // // int N3: the size of the data set 3. // // double T3(N3), Y3(N3), dataset 3. // // int N3: the size of the data set 4. // // double T4(N4), Y4(N4), dataset 4. // // string HEADER: an identifier for the data. // // string TITLE: a title to appear in the plot. // { string command_filename; ofstream command; string data1_filename; string data2_filename; string data3_filename; string data4_filename; ofstream data; int i; // // Create the data files. // data1_filename = header + "_data1.txt"; data.open ( data1_filename.c_str ( ) ); for ( i = 0; i < n1; i++ ) { data << " " << t1[i] << " " << y1[i] << "\n"; } data.close ( ); data2_filename = header + "_data2.txt"; data.open ( data2_filename.c_str ( ) ); for ( i = 0; i < n2; i++ ) { data << " " << t2[i] << " " << y2[i] << "\n"; } data.close ( ); data3_filename = header + "_data3.txt"; data.open ( data3_filename.c_str ( ) ); for ( i = 0; i < n3; i++ ) { data << " " << t3[i] << " " << y3[i] << "\n"; } data.close ( ); data4_filename = header + "_data4.txt"; data.open ( data4_filename.c_str ( ) ); for ( i = 0; i < n4; i++ ) { data << " " << t4[i] << " " << y4[i] << "\n"; } data.close ( ); cout << "\n"; cout << " plot4: data stored in '" << data1_filename << "', '" << data2_filename << "', '" << data3_filename << "', '" << data4_filename<< "'\n"; // // Create the command file. // command_filename = header + "_commands.txt"; command.open ( command_filename.c_str ( ) ); command << "# " << command_filename << "\n"; command << "#\n"; command << "# Usage:\n"; command << "# gnuplot < " << command_filename << "\n"; command << "#\n"; command << "set term png\n"; command << "set output '" << header << ".png'\n"; command << "set xlabel '<-- T -->'\n"; command << "set ylabel '<-- Y(T) -->'\n"; command << "set title '" << title << "'\n"; command << "set grid\n"; command << "set style data lines\n"; command << "plot '" << data1_filename << "' using 1:2 with lines lw 3 lt rgb 'red',\\\n"; command << " '" << data2_filename << "' using 1:2 with lines lw 3 lt rgb 'blue',\\\n"; command << " '" << data3_filename << "' using 1:2 with lines lw 3 lt rgb 'green',\\\n"; command << " '" << data4_filename << "' using 1:2 with lines lw 3 lt rgb 'magenta'\n"; command << "quit\n"; command.close ( ); cout << " plot4: plot commands stored in '" << command_filename << "'.\n"; return; } //****************************************************************************80 double *r8vec_linspace_new ( int n, double a_first, double a_last ) //****************************************************************************80 // // Purpose: // // r8vec_linspace_new() creates a vector of linearly spaced values. // // Discussion: // // An R8VEC is a vector of R8's. // // 4 points evenly spaced between 0 and 12 will yield 0, 4, 8, 12. // // In other words, the interval is divided into N-1 even subintervals, // and the endpoints of intervals are used as the points. // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 29 March 2011 // // Author: // // John Burkardt // // Input: // // int N, the number of entries in the vector. // // double A_FIRST, A_LAST, the first and last entries. // // Output: // // double R8VEC_LINSPACE_NEW[N], a vector of linearly spaced data. // { double *a; int i; a = new double[n]; if ( n == 1 ) { a[0] = ( a_first + a_last ) / 2.0; } else { for ( i = 0; i < n; i++ ) { a[i] = ( ( double ) ( n - 1 - i ) * a_first + ( double ) ( i ) * a_last ) / ( double ) ( n - 1 ); } } return a; } //****************************************************************************80 void timestamp ( ) //****************************************************************************80 // // Purpose: // // timestamp() prints the current YMDHMS date as a time stamp. // // Example: // // 31 May 2001 09:45:54 AM // // Licensing: // // This code is distributed under the MIT license. // // Modified: // // 19 March 2018 // // Author: // // John Burkardt // { # define TIME_SIZE 40 static char time_buffer[TIME_SIZE]; const struct std::tm *tm_ptr; std::time_t now; now = std::time ( NULL ); tm_ptr = std::localtime ( &now ); std::strftime ( time_buffer, TIME_SIZE, "%d %B %Y %I:%M:%S %p", tm_ptr ); std::cout << time_buffer << "\n"; return; # undef TIME_SIZE }