/*
*/LIBRERIA DORMAND PRINCE Javascript - MAGGIO 2014.
Con estensione HTML posso ottenere persino scritte rosse! In rete:
http://www.elegio.it/calcolatrice/libreria-dormand-prince.js.html
http://www.elegio.it/calcolatrice/nuova-dormand-prince.html*/ // // Questa e' la funzione fondamentale. // Richiede in argomento fder(x,y,costa) ossia la funzione da usare // nel Runge Kutta e che deve produrre come risultato // un vettore. // Il primo argomento di fder e' il vettore delle incognite // ossia le posizioni e le velocita' // Il secondo argomento di fder e' il vettore delle variazioni // Il terzo argomento di fder e' il vettore delle costanti usate // che non vanno cambiate ma solo usate. // // Il significato degli altri argomenti e' questo: // // x0 == Valore iniziale della variabile indipendente. // y0 == Valore iniziale del vettore delle variabili dipendenti. // x1 == Valore finale desiderato della variabile indipendente. // costa == Costanti usate per calcolare le derivate prime delle // variabili dipendenti che all'inizio valgono y1. // peso == Vettori usato per equilibrare l'importanza degli errori // del calcolo. Spesso l'errore di una qualche variabile // ha importanza molto diversa dall'errore di una qualche // altra variabile. // tol == parametro usato per limitare l'errore. Piu' e' piccolo // e maggiore e' la precisione ossia minore la tolleranza // dell'errore totale ottenuto come somma degli errori // delle varie variabili pesati sul peso della loro importanza. // function odedopri(fder,x0,y0,x1,costa,peso,tol,maxiter){ var ha21,ha31,ha32,ha41,ha42,ha43,ha51,ha52,ha53,ha54, ha61,ha62,ha63,ha64,ha65,ha71,ha73,ha74,ha75,ha76; var e1,e3,e4,e5,e6,e7; var i,j,ifa,x,ny,h,hmax,hmin,verrore,erromax; var y=[0],z=[0],k1=[0],k2=[0],k3=[0],k4=[0],k5=[0],k6=[0],k7=[0]; x=x0; ny=y0.length; // alert("ny = "+ny); for(j=1;ny>j;j++)y[j]=y0[j]; h=10*(x1-x0)/(maxiter*171362822400); hmax=h; hmin=h/100; erromax=0; amen=false; e1=211228479; e3=-728766720; e4=6336854370; e5=-8716163841; e6=7180918272; e7=-4284070560; k1=fder(x,y,costa); // // alert("Stampo k1 \n"+k1); // for(i=1;maxiter>=i;i++){ ifa=i; ha21=34272564480*h; for(j=1;ny>j;j++)z[j]=y[j]+ha21*k1[j]; k2=fder(x+34272564480*h,z,costa); ha31=12852211680*h; ha32=38556635040*h; for(j=1;ny>=j;j++)z[j]=y[j]+ha31*k1[j]+ha32*k2[j]; k3=fder(x+51408846720*h,z,costa); ha41=167554759680*h; ha42=-639754536960*h; ha43=609290035200*h; for(j=1;ny>j;j++)z[j]=y[j]+ha41*k1[j]+ha42*k2[j]+ ha43*k3[j]; k4=fder(x+137090257920*h,z,costa); ha51=505965644800*h; ha52=-1987087872000*h; ha53=1683278643200*h; ha54=-49833907200*h; for(j=1;ny>j;j++)z[j]=y[j]+ha51*k1[j]+ha52*k2[j]+ ha53*k3[j]+ha54*k4[j]; k5=fder(x+152322508800*h,z,costa); ha61=487745760600*h; ha62=-1843448544000*h; ha63=1526229734400*h; ha64=47708967600*h; ha65=-46873096200*h; hc6=171362822400*h; for(j=1;ny>j;j++)z[j]=y[j]+ha61*k1[j]+ha62*k2[j]+ ha63*k3[j]+ha64*k4[j]+ha65*k5[j]; k6=fder(x+hc6,z,costa); ha71=15619007250*h; ha73=76982400000*h; ha74=111564337500*h; ha75=-55243291950*h; ha76=22440369600*h; for(j=1;ny>j;j++)z[j]=y[j]+ha71*k1[j]+ ha73*k3[j]+ha74*k4[j]+ha75*k5[j]+ha76*k6[j]; k7=fder(x+171362822400*h,z,costa); // erromax=0; for(j=1; ny>j; j++){verrore=peso[j]* Math.abs(e1*k1[j]+e3*k3[j]+e4*k4[j]+e5*k5[j]+ e6*k6[j]+e7*k7[j]); if(verrore>erromax)erromax=verrore;} // if(tol>erromax/171362822400){avanti=true;} else{ if(hc6>hmin){h=h/2;avanti=false;} else { avanti=true; } amen=false;} // if(avanti){ x=x+hc6; for(j=1; ny>j; j++){ y[j]=y[j]+ha71*k1[j]+ha73*k3[j]+ha74*k4[j]+ ha75*k5[j]+ha76*k6[j]; k1[j]=k7[j]}; if(amen){break}; if(hmax>h)h=1.05*h; } if(x+h*171362822400>x1){ h=(x1-x)/171362822400;amen=true}; // }; // // amen vale true se ha fatto tutto, altrimenti false. // ifa indica il numero di iterazioni fatte realmente. // return [0,amen,x,y,ifa]; } // // __________________________________________________________ // // CASI PROVA LIBRERIA DORMAND PRINCE // // Ogni caso e' basato su due funzioni. La funzione da integrare // e la funzione che fa l'inizializzazione dei dati del calcolo. // // Le seguenti sono le variabili d'ambiente utilizzate: // // var tol=1.0e-13,maxiter=250; var x_0,x_1,y_0,costa,peso; // // // Primo caso prova, elementare... // // function primafder(x,y,c){ var rr; rr=Math.exp(2*x)/2; return [0,1,rr+1.5*y[2]]; } // function ini_fder1(){ x_0=0; x_1=1; y_0=[0,0,1]; costa=[0,1]; peso=[0,1,1]; tol=1.0e-13; maxiter=250; return [0,x_0,y_0,x_1,costa,peso,tol,maxiter] } // // // Secondo caso prova leggermente piu' complicato. // // function secondafder(x,v,c){ var y,z; y=v[1]; z=v[2]; return [0,z/2,-2*y]; } // function ini_fder2(){ x_0=0; x_1=1.5*Math.PI; y_0=[0,0,2]; costa=[0,1]; peso=[0,1,1]; tol=1.0e-13; maxiter=2000; return [0,x_0,y_0,x_1,costa,peso,tol,maxiter] } // // // Terzo caso prova: moto piano ( bidimensionale ) di asteroide // attorno al Sole. // // function terzafder(t,v,c){ var x,y,vx,vy,mu,rq,rr,den,x_,y_,vx_,vy_; x=v[1]; y=v[2]; vx=v[3]; vy=v[4]; mu=c[1]; x_=vx; y_=vy; rq=x*x+y*y; rr=Math.sqrt(rq); den=1/(rr*rq); vx_=-mu*x*den; vy_=-mu*y*den; // // Il risultato e' il vettore delle quattro variabili ossia: // la derivata della posizione in ascissa, // la derivata della posizione in ordinata, // la derivata della velocita' in ascissa, // la derivata della velocita' in ordinata. // return [0,x_,y_,vx_,vy_]; } // function ini_fder3(){ // velocita' media, al perielio, all'afelio, eccentricita'... var vm,vp,va,ec; costa=[0,1.327581e20,149.61e9,30500.0]; vm=Math.sqrt(costa[1]/costa[2]); if(costa[3]>vm){vp=costa[3];va=vm*vm/vp;} else {va=costa[3];vp=vm*vm/va}; ec=(vp-va)/(vp+va); x_0=0; x_1=2*Math.PI*costa[2]/vm; y_0=[0,costa[2]*(1-ec),0,0,vp]; peso=[0,1.0e-9,1.0e-9,1.0e-4,1.0e-4]; tol=5.0e-14; maxiter=500; return [0,x_0,y_0,x_1,costa,peso,tol,maxiter]; } // //_________________________________________________________________ // // Problema di tre corpi nel piano ( Terra e Luna // attorno al Sole immobile ) // xt e yt sono l'ascissa e l'ordinata della Terra, // xl e yl sono l'ascissa e l'ordinata della Luna. // x sarebbe il tempo che pero' non interviene esplicitamente // nel calcolo delle derivate prime. // vxt e vyt sono la velocita' della Terra in ascissa e in ordinata. // vxl e vyl sono la velocita' della Luna in ascissa e in ordinata. // dunque le variabili sono in totale 8 e di queste la funzione // deve produrre le loro derivate prime. // Nel caso delle posizioni ossia le prime 4 variabili, le derivate // prime sono ovviamente le velocita'. // Nel caso delle velocita' ossia le variabili dalla quinta alla // ottava, le derivate prime sono ovviamente le forze. // // function quartafder(x,v,c){ var mu,ts,xt,yt,vxt,vyt,rqt,rrt,dent,xt_,yt_,vxt_,vyt_; var dentl,denlt,ls,xl,yl,vxl,vyl,rql,rrl,denl,xl_yl_,vxl_vyl_; // // Ricopia il vettore delle coordinate solo per rendere // piu' leggibile questa funzione. // xt=v[1]; yt=v[2]; xl=v[3]; yl=v[4]; vxt=v[5]; vyt=v[6]; vxl=v[7]; vyl=v[8]; // // mu e' la azione gravitazionale del Sole ossia la sua massa per G // ossia la costante di gravitazione universale. // ts e' il rapporto tra la massa della Terra e quella del Sole // ls e' il rapporto tra la massa della Luna e quella del Sole... // mu=c[1]; ts=c[2]; ls=c[3]; // // Ovviamente le derivate prime delle velocita' della Terra e della // Luna sono le velocita' ( bidimensionali, in ascissa e ordinata ) // xt_=vxt; yt_=vyt; xl_=vxl; yl_=vyl; // // rqt e' il quadrato della distanza della Terra dal Sole. // rqt=xt*xt+yt*yt; // // rrt e' la distanza della Terra dal Sole. // rrt=Math.sqrt(rqt); // // l'inverso del cubo della distanza tra la Terra e in Sole. // dent=1/(rrt*rqt); // // rql e' il quadrato della distanza della Luna dal Sole. // rql=xl*xl+yl*yl; // // rrl e' la distanza della Luna dal Sole. // rrl=Math.sqrt(rql); // // l'inverso del cubo della distanza tra la Luna e il Sole. // denl=1/(rrl*rql); // // rqtl e' il quadrato della distanza della Luna dalla Terra. // rqtl=(xt-xl)*(xt-xl)+(yt-yl)*(yt-yl); // // rrtl e' la distanza della Luna dalla Terra. // rrtl=Math.sqrt(rqtl); // // per velocizzare i calcoli precalcolo queste due quantita' // dentl=ls/(rqtl*rrtl); denlt=ts/(rqtl*rrtl); // // le forze sulla Terra in ascissa ed in ordinata. Per // ottenere una forza attrattiva la forza deve avere il // segno meno. // vxt_=-mu*(xt*dent+(xt-xl)*dentl); vyt_=-mu*(yt*dent+(yt-yl)*dentl); // // le forze sulla Luna in ascissa ed in ordinata // vxl_=-mu*(xl*denl+(xl-xt)*denlt); vyl_=-mu*(yl*denl+(yl-yt)*denlt); return [0,xt_,yt_,xl_,yl_,vxt_,vyt_,vxl_,vyl_]; } // _____________________________________________________________ // // Produce un vettore di dati di questo quarto test ossia: // 1== L'istante di tempo assunto come iniziale // 2== Il vettore delle condizioni iniziali ossia le posizioni // delle particelle e le velocita' delle particelle. // 3== L'istante di tempo che bisogna raggiungere. // 4== Le costanti da usare per calcolare le forze ossia // le accelerazioni. // 5== Il vettore di equilibramento delle tolleranze degli errori. // 6== Il parametro di controllo dell'errore, piccolissimo // se molto preciso. // 7== Il numero massimo delle iterazioni ammesse per fare // evolvere il sistema fino alla fine. // function ini_fder4(){ var vm,vp,va,ec; // // Le costanti usate sono: // 1== la costante gravitazionale solare ossia // la massa del sole per la G ossia costante di // gravitazione universale. // 2== Il rapporto tra la massa della Terra e la massa del Sole. // 3== Il rapporto tra la massa della Luna e la massa del Sole // e la massa della Luna e' circa un ottantesimo della massa // della terra per cui uso questo dato... // 4== La distanza iniziale della Terra dal Sole. // 5== La velocita' in metri al secondo della Terra. // costa=[0,1.327581e20, 1/333000.1, 1/(333000.1*80), 149.61e9, 30500.0]; vm=Math.sqrt(costa[1]/costa[4]); if(costa[5]>vm){vp=costa[5];va=vm*vm/vp;} else {va=costa[5];vp=vm*vm/va; }; ec=(vp-va)/(vp+va); // // x_0 e' l'istante iniziale del transitorio. // x_0=0; // // x_1 e' l'istante finale a cui vorrei arrivare nella simulazione. // x_1=2*Math.PI*costa[4]/vm; // // y_0 e' il vettore delle incognite: 4 posizioni e 4 velocita'. // y_0=[0,costa[4]*(1-ec),0,costa[4]*(1-ec),-360e6,0,vp,1100.0,vp]; // // il vettore peso controlla la tolleranza del calcolo // Il peso delle posizioni deve essere molto piccolo // rispetto ai pesi delle velocita' perche' le // posizioni si misurano in miliardi di metri e le // velocita' si misurano in decine di migliaia di metri al secondo. // peso=[0,1e-9,1e-9,1e-9,1e-9,1e-4,1e-4,1e-4,1e-4]; // // Il criterio di tolleranza piuttosto severo... // tol=0.5e-14; // // il massimo numero delle iterazioni consentite: // maxiter=2000; // // Ecco il vettore risultato usabile per inizializzare i calcoli. // Notare che tutti questi dati sono variabili globali // e non locali mentre il vettore risultato e' solo una raccolta // di queste variabili globali inizializzate da questa funzione. // return [0,x_0,y_0,x_1,costa,peso,tol,maxiter]; } // // ____________________________________________________________________ // //PER PILOTARE I CASI PROVA DELLA LIB. DORMAND PRINCE // // Devono esistere le seguenti MARCHE HTML: // // Per il primo caso prova : "x100", "x101", "x102". // Per il secondo caso prova : "x200", "x201", "x202". // Per il terzo caso prova : "x300", "x301", "x302". // Per il quarto caso prova : "x400", "x401", "x402", "x403". // function test_casi_prova_libreria(){ var obs,ob,p1,ris3,ris4,ris5,inforis1,inforis2; // // ====================================================== // Prima prova. // Il risultato finale dovrebbe essere [1,7.38905609893065] // p1=ini_fder1(); inforis1=[0,"var.indip.x", "x considerato dipendente","y","x finale","costa", "xpeso","ypeso","tolleranza","iterazioni massime"]; inforis2=[0,"Bene se true, male se false","x","xdip","y", "iterazioni fatte" ]; ob=document.getElementById("x100"); ob.innerHTML="Dati di inizializzazione del primo test "+ vedoris(p1,inforis1); ris3=odedopri(primafder,x_0,y_0,x_1,costa,peso,tol,maxiter); ob=document.getElementById("x101"); ob.innerHTML="Avendo fatto al massimo "+maxiter+" iterazioni "+ " non dovrebbe riuscire a trovare la soluzione "+ vedoris(ris3,inforis2); if(!ris3[1])ris4=odedopri(primafder,ris3[2],ris3[3],x_1, costa,peso,tol,4*maxiter); ob=document.getElementById("x102"); ob.innerHTML="Risultato finale avendo "+ " quadruplicato il massimo delle iterazioni ammesse "+ vedoris(ris4,inforis2); // // ====================================================== // // Seconda prova. // Il risultato finale dovrebbe essere [-1,0] // p1=ini_fder2(); inforis1=[0,"varindip.iniz.x","y","z","varindip.finale", "cost","ypeso","zpeso","tolleranza","maxpassi"]; inforis2=[0,"Bene se true, male se false","xfinale", "yfinale","zfinale","iterazionifatte"]; ob=document.getElementById("x200"); ob.innerHTML="Dati di inizializzazione del secondo test "+ vedoris(p1,inforis1); ris3=odedopri(secondafder,x_0,y_0,x_1,costa,peso,tol,maxiter); ob=document.getElementById("x201"); ob.innerHTML="Avendo fatto al massimo "+maxiter+" iterazioni "+ "non trova la soluzione"+ vedoris(ris3,inforis2); if(!ris3[1])ris4=odedopri(secondafder,ris3[2],ris3[3],x_1, costa,peso,tol,4*maxiter); ob=document.getElementById("x202"); ob.innerHTML="Risultato finale con il quadruplo di iterazioni"+ " che non usa se non quando servono al criterio "+ " di cambio ampiezza passo "+vedoris(ris4,inforis2); // // ============================================================== // // Terza prova. // Il risultato finale dovrebbe essere : // [146079760576.14456,0,0,30500] // p1=ini_fder3(); inforis1=[0,"t-iniziale","xaster","yaster","vxaster","vyaster", "t_finale","costaG*M","costa_amaggiore","costavmedia", "xpeso","ypeso","vxpeso","vypeso","tolleranza","Maxiterazioni"]; inforis2=[0,"Bene se true, male se false", "t_finale","xfinale","yfinale","vxfinale","vyfinale", "iterazionifatte"]; ob=document.getElementById("x300"); ob.innerHTML="Dati di inizializzazione del terzo test "+ vedoris(p1,inforis1); ris3=odedopri(terzafder,x_0,y_0,x_1,costa,peso,tol,maxiter); ob=document.getElementById("x301"); ob.innerHTML="Avendo fatto al massimo "+maxiter+" iterazioni "+ " in questo caso riesce al primo colpo "+ vedoris(ris3,inforis2); if(!ris3[1])ris4=odedopri(terzafder,ris3[2],ris3[3],x_1, costa,peso,tol,maxiter) else ris4=ris3; ob=document.getElementById("x302"); ob.innerHTML="Risultato finale "+vedoris(ris4,inforis2); // // ============================================================ // // Quarta prova che commento in dettaglio... // Il risultato finale dovrebbe essere ??? // // Innanzi tutto calcola i dati che servono per impostare i calcoli // p1=ini_fder4(); inforis1=[0,"t-iniziale","xterra","yterra","xluna","yluna","vxterra", "vyterra","vxluna","vyluna","t-finale","costa G*Msole", "Mterrasusole","Mlunasusole","Distadalsole","Vtangen", "pesoxt","pesoyt","pesoxl","pesoyl","pesovxt", "pesovyt","pesovxl","pesovyl","tollera","Maxpassi"]; inforis2=[0,"Bene se true ma male se false","t-finale", "xtfin","ytfin","xlfin","ylfin","vxtfin","vytfin","vxlfin", "vylfin","Iterfatte"]; ob=document.getElementById("x400"); ob.innerHTML="Dati di inizializzazione del quarto test "+ vedoris(p1,inforis1); // // Poi fa un numero massimo di 20 iterazioni. // ris3=odedopri(quartafder,x_0,y_0,x_1,costa,peso,tol,20); ob=document.getElementById("x401"); ob.innerHTML="Avendo fatto preliminarmente "+20+" iterazioni "+ vedoris(ris3,inforis2); // // Se le sole 20 iterazioni non sono bastate ad ottenere true // fa realmente un altro gruppo di maxiter iterazioni, ma se sono // bastate le prime 20 ad arrivare al tempo x_1, non ripete il calcolo... // Notare che ris3[2] e' il tempo a cui e' riuscito ad arrivare con 20 // iterazioni e ris3[3] e' il vettore delle condizioni iniziali. // if(!ris3[1])ris4=odedopri(quartafder,ris3[2],ris3[3],x_1, costa,peso,tol,maxiter) else ris4=ris3; ob=document.getElementById("x402"); ob.innerHTML="Avendo fatto preliminarmente "+maxiter+ " iterazioni non ce la fa "+vedoris(ris4,inforis2); // // Se non e' riuscito a raggiungere il tempo x_1 rifa' un altro // blocco di maxiter iterazioni sperando che almeno questo terzo tentativo // gli consenta di arrivare alla conclusione ossia al tempo x_1 desiderato. // if(!ris4[1])ris5=odedopri(quartafder,ris4[2],ris4[3],x_1, costa,peso,tol,maxiter) else ris5=ris4; // ob=document.getElementById("x403"); ob.innerHTML="Risultato finale ottenuto ridando "+ "i due dati, tempo e valori ottenuti "+ "e facendo un altro blocco di iterazioni con successo "+ vedoris(ris5,inforis2); // } // //_________________________________________________________________________ // // Una funzione di servizio per trasformare vettori // e vettori di vettori in stringhe. // function vedoris(rr,inforr){ // Visualizza il vettore rr var j,pn=[],npn,paragrafo,zz,ta=typeof([0]), ss=" {\u2192 ",nn=rr.length; if(arguments.length>2)paragrafo=arguments[2]; else {paragrafo=[],inforr[0]=0}; npn=paragrafo.length; for(j=0;npn>j;j++)pn[j]=paragrafo[j]; pn[npn]=0; for(j=1;nn>j;j++){ pn[npn]=j; if(typeof(rr[j])==ta) { zz=vedoris(rr[j],inforr,pn); ss+="[\u00ab"+pn+"\u00bb: "+zz+"] "; } else { zz=rr[j]; inforr[0]=Math.min(inforr[0]+1,inforr.length-1); ss+="[\u00ab"+pn+":"+inforr[inforr[0]]+ "\u00bb: "+zz+"] ";} }; return ss+" \u2190} "; } // // // Funzione generica per salvare nella libreria voluta ossia lib, // nell'elemento qui ( se e' stato creato oppure in coda ) // i dati contenuti in rr che puo' essere un dato o una lista o // una lista contenente altre liste... // function salvinlib(lib,qui,rr){ var nn=Math.min(qui,lib.length); lib[nn]=[]; salvorr(lib[nn],rr); } // function salvorr(lista,rr){ var j,mm,nn=rr.length,ta=typeof([0]); // Salva tutto quello che sta in rr for(j=0;nn>j;j++){ mm=lista.length; if(typeof(rr[j])==ta){ lista[mm]=[]; salvorr(lista[mm],rr[j]);} else lista[mm]=rr[j]; } } // /*AMEN LIBRERIA DORMAND PRINCE - MAGGIO 2014