Mi servirebbe aiuto con un integratore di equazioni differenziali: ho messo la scheda negli allegati
Adesso non so se mostrarvi il mio codice qui o direttamente darvi anche quello come file, siccome è abbastanza lungo
Vabbè lo metto in code poi se è necessario uploado il file direttamente.
Ho fatto più o meno quello che mi è stato chiesto (almeno credo): tuttavia, ho implementato il RungeKutta 2nd order non come è scritto nella scheda, ma secondo la notazione del libro Numerical Recipes in C consigliatoci dal professore.
Non so se la mia implementazione sia corretta: ho fatto entrambi i punti 1 e 2(il secondo tramite un file bash e poi plottando con un for loop in gnuplot). è sorto questo problema: se runnate su un compiler online e inserendo i parametri otterrete questo:
N = 0, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 1.5005478528675606 v = -100.0497285075012428
N = 2, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.6636376775159283 v = 0.1073845956605055
N = 1, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.6030424837371133 v = 0.0696976399374857
N = 3, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.7045182928011882 v = 0.1050771817756628
N = 4, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.7345036132091616 v = 0.1031850670880924
N = 5, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.7577350957939557 v = 0.1015888677781990
N = 6, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.7764213062976668 v = 0.1002059937837422
N = 7, t0 = 0.010000, x0 = 1.000000, v0 = 0.000000, dt = 0.010000, tmax = 100.000000
t[10000] = 100.0000000000000142 x = 0.7918693982489068 v = 0.0989846199936164
Fin qui mi sembrava tutto ok. Poi però ho plottato la coordinata $P$ in funzione di $r$ ( io nel codice ho definito $P, D, r$ come $x, v, t$ per abitudine) e ho notato che per tutti gli $n$ da $0 \to 7$ nessuna delle curve interseca l'asse x (ovvero P(che è il mio x) non si annulla mai nel tempo di integrazione).
Tuttavia nel punto dopo chiede di trovare i valori di $R$(ovvero $t$) per cui $P(R)$ si annulla
Se qualcuno potesse gentilmente dirmi dove e cosa sto sbagliando (credo che non ci siano errori nella funzione dove implemento l'algoritmo, forse sbaglio altrove). Ho fatto un po' di debugging con dei printf e mi è sembrato che tutto fosse giusto. Grazie mille in anticipo.
Vorrei specificare che il mio livello di conoscenza del C è davvero basso e si limita alle cose presenti nel programma da me scritto, quindi vi chiedo, nel caso di spiegazioni, di non essere troppo crudeli, e soprattutto di suggerire correzioni all'interno del file.c che ho messo.
Ringrazio in anticipo chi avrà voglia di darmi una mano f1
(P.S.ho iniziato da pochissimo gli algoritmi di integrazione di ODEs)
- Codice:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/***********STRUCTS**************/
struct Point_t {
double x;
double v;
};
typedef struct Point_t Point;
struct Params_t {
int n;
};
typedef struct Params_t Params;
/*********STRUCT FUNCTIONS DECLARATION***********/
void pSum(Point *res, Point *sum);
void pMul(double factor, Point *res);
void HPMul(double factor, Point *res);
void pFma(double factor, Point *res, Point *p1, Point *p2);
void pCpy(Point *pIn, Point *pOut);
void pSet(double val1, double val2 , Point *pIn);
void printP(Point *pIn);
/*********PROBLEM FUNCTIONS DECLARATION**********/
void drift(Point *pIn, Point *pOut, double t, Params *parameters);
void RK2(Point *pIn, Point *pOut, double t, double dt, Params *parameters);
/***********MAIN**************/
int main(int argc, char *argv[]) {
FILE *fp;
int i = 0;
int N = atoi(argv[1]);
double t0 = atof (argv[2]);
double x0 = atof(argv[3]);
double v0 = atof(argv[4]);
double dt = atof(argv[5]);
double tmax = atof(argv[6]);
printf("N = %d, t0 = %lf, x0 = %lf, v0 = %lf, dt = %lf, tmax = %lf\n", N, t0, x0, v0, dt, tmax);
double numberofSteps = (int) (tmax / dt -0.5) ; // approximate to the nearest bigger integer
Point old_xv, new_xv;
//Assign the initial values
old_xv.x = x0;
old_xv.v = v0;
Point *pIn, *pOut;
pIn = &old_xv;
pOut = &new_xv;
Params parameters;
parameters.n = N;
/*test of drift functions-----------------drift(pIn, pOut, t0, ¶meters); works*/
/*Point *null;
Point zero;
zero.x = 0;
zero.v = 0;
null = &zero;*/
/* Test the first iteration with known outputs RK2(pIn,pOut, t0, dt, ¶meters); works*/
for (i = 0; i <= numberofSteps; ++i) {
Point *tmp;
double t = t0 + dt*i;
//printf("t[%d] = %.16lf x[%d] = %.16lf v[%d] = %.16lf\n", i, t, i, pIn->x, i, pIn->v);
RK2(pIn, pOut, t, dt, ¶meters);
tmp = pIn;
pIn = pOut;
pOut = tmp;
}
printf("t[%d] = %.16lf x = %.16lf v = %.16lf\n", i, (double) (t0+dt*(numberofSteps)), pOut->x, pOut->v);
/*fp = fopen("data.dat", "w+");
if ( ( fp=fopen("data.dat", "w+") ) == NULL) {
printf("Couldn't open the file...Terminating\n");
exit(1);
}
for (i = 0; i <= numberofSteps; ++i) {
Point *tmp;
double t = t0 + dt*i;
fprintf(fp, "%.16lf %.16lf %.16lf\n", t, pIn->x, pIn->v);
if (t == 80.) break;
RK2(pIn, pOut, t, dt, ¶meters);
tmp = pIn;
pIn = pOut;
pOut = tmp;
}
fclose(fp);*/
return 0;
}
/**************PROBLEM FUNCTIONS***************/
void drift(Point *pIn, Point *pOut, double t, Params *parameters) {
//printf("n = %d\n", parameters->n);
pOut->x = pIn->v;
pOut->v = - pow(pIn->x, parameters->n) - ( 2. / t ) * pIn->v;
}
void RK2(Point *pIn, Point *pOut, double t, double dt, Params *parameters) {
/* some temporary structs for help */
double new_dt = 0.;
Point tmp, tmp2;
Point K1, K1dt;
Point K2, K2dt;
Point result;
/* RungeKutta2 Implementation */
//printP(pIn);
drift (pIn, &K1, t, parameters);
//printP(&K1);
HPMul(dt, &K1);
pCpy(&K1, &K1dt);
//printP(&K1dt);
new_dt = dt * 0.5 ;
pCpy(&K1, &tmp);
//printP(&tmp);
HPMul(0.5, &tmp);
//printP(&tmp);
drift(&tmp, &K2, t+new_dt , parameters);
//printP(&K2);
pCpy(&K2, &K2dt);
HPMul(dt, &K2dt);
//printP(&K2dt);
pCpy(&K2dt, &result);
pSum(&result, pIn);
//printP(&result);
pCpy(&result, &tmp2);
//printP(&tmp2);
pCpy(&tmp2, pOut);
//printP(pOut);
}
/*********STRUCT FUNCTIONS (Tested beforehand)********/
void pSum(Point *res, Point *sum) {
res->x = res->x + sum->x;
res->v = res->v + sum->v;
}
void pMul(double factor, Point *res) {
res->x = factor * res->x;
res->v = factor * res->v;
}
void pFma(double factor, Point *res, Point *p1, Point *p2) { // fma(factor, p1, p2) --> res = (factor * p1) + p2 at higher precision
res->x = fma(factor, p1->x, p2->x);
res->v = fma(factor, p1->v, p2->v);
}
void HPMul(double factor, Point *res) {
Point add;
add.x = 0;
add.v = 0;
Point *Null;
Null = &add;
res->x = fma(factor, res->x, Null->x);
res->v = fma(factor, res->v, Null->v);
}
void pCpy(Point *pIn, Point *pOut) {
pOut->x = pIn->x;
pOut->v = pIn->v;
}
void pSet(double val1, double val2, Point *pIn) {
if ( val2 == 0. ) {
pIn->x = val1;
pIn->v = val1;
}
else {
pIn->x = val1;
pIn->v = val2;
}
}
void printP(Point *pIn) {
printf("x = %.8lf \t v = %.8lf\n", pIn->x, pIn->v) ;
}
Questo il plot per $n = 0 \to 4$