kernel.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #include "kernel.hpp"
  2. Kernel::Kernel(string filename){
  3. fstream file;
  4. file.open(filename.c_str(),fstream::in|fstream::binary);
  5. InputData::load(file,true);
  6. initSolutions();
  7. Solution& S0=*solution[0];
  8. //Init pressure
  9. for(size_t x=0;x<geometry.nX;++x){
  10. for(size_t z=0;z<geometry.nZ[x];++z){
  11. S0.P[x][z]=initial_state->Pinit[x][z];
  12. }
  13. }
  14. //Init hydraulic head
  15. for(size_t x=0;x<geometry.nX;++x){
  16. S0.hydr[x]=initial_state->hsat[x]+Psat/(Physics::rho*Physics::g);
  17. }
  18. //Init overland level
  19. for(size_t x=0;x<geometry.nX;++x){
  20. S0.hov[x]=Physics::invPsol(geometry.hsoil[x],S0.P[x][geometry.nZ[x]-1]); //TODO[Chrisophe] à initiliser
  21. }
  22. //Init l
  23. for(size_t x=0;x<geometry.nX;++x){
  24. double t=initial_state->hsat[x];
  25. S0.l[x]=t;
  26. S0.hsat[x]=t;
  27. }
  28. //Init Pl
  29. for(size_t x=0;x<geometry.nX;++x){
  30. S0.Pl[x]=Psat;
  31. }
  32. indice_x_Richards=new bool[geometry.nX];
  33. div_w=new double*[geometry.nX];
  34. P_temp=new double*[geometry.nX];
  35. for(size_t i=0;i<geometry.nX;++i){
  36. div_w[i]=new double[geometry.nZ[i]];
  37. P_temp[i]=new double[geometry.nZ[i]];
  38. }
  39. t_sub_A=new double*[geometry.nX];
  40. t_sub_B=new double*[geometry.nX];
  41. t_sub_C=new double*[geometry.nX];
  42. t_diag_A=new double*[geometry.nX];
  43. t_diag_B=new double*[geometry.nX];
  44. t_diag_C=new double*[geometry.nX];
  45. t_sup_A=new double*[geometry.nX];
  46. t_sup_B=new double*[geometry.nX];
  47. t_sup_C=new double*[geometry.nX];
  48. t_F=new double*[geometry.nX];
  49. t_G=new double*[geometry.nX];
  50. t_S=new double*[geometry.nX];
  51. t_H=new double*[geometry.nX];
  52. t_R=new double*[geometry.nX];
  53. t_I=new double*[geometry.nX];
  54. t_BB=new double*[geometry.nX];
  55. for(size_t i=0;i<geometry.nX;++i){
  56. size_t nZ=geometry.nZ[i];
  57. t_sub_A[i]=new double[nZ-2];
  58. t_sub_B[i]=new double[nZ-2];
  59. t_sub_C[i]=new double[nZ-2];
  60. t_diag_A[i]=new double[nZ-1];
  61. t_diag_B[i]=new double[nZ-1];
  62. t_diag_C[i]=new double[nZ-1];
  63. t_sup_A[i]=new double[nZ-2];
  64. t_sup_B[i]=new double[nZ-2];
  65. t_sup_C[i]=new double[nZ-2];
  66. t_F[i]=new double[nZ-1];
  67. t_G[i]=new double[nZ-1];
  68. t_S[i]=new double[nZ-1];
  69. t_H[i]=new double[nZ-1];
  70. t_R[i]=new double[nZ-1];
  71. t_I[i]=new double[nZ-1];
  72. t_BB[i]=new double[nZ-1];
  73. }
  74. delete initial_state;
  75. initial_state=nullptr;
  76. file.close();
  77. step=0;
  78. m=1;
  79. scheme_error=0;
  80. }
  81. void
  82. Kernel::initSolutions(){
  83. Solution* S0=new Solution();
  84. S0->init(geometry);
  85. solution[0]=S0;
  86. for(size_t i=1;i<=Time::nT;++i) solution[i]=nullptr;
  87. for(size_t i=0;i<Time::nT+2;++i){
  88. Solution* S=new Solution();
  89. S->init(geometry);
  90. pool_solutions.push(S);
  91. }
  92. }
  93. bool
  94. Kernel::next(){
  95. //cout<<"[Kernel::next]"<<endl;
  96. if(m>1) m=m/2;
  97. spaceSolution();
  98. if(scheme_error>0) return false;
  99. ++step;
  100. //cout<<"[next] done"<<endl;
  101. return true;
  102. }
  103. void
  104. Kernel::spaceSolution(){
  105. //cout<<"[Kernel::spaceSolution]"<<endl;
  106. size_t n=step+1; //We want solution at time n
  107. size_t k=0; //we work on time interval [n-1+k/m,n-1+(k+1)/m]
  108. Solution *S=solution[step];
  109. while(m<=max_time_subdivisions){
  110. //cout<<" k,m = "<<k<<','<<m<<endl;
  111. S=Piccard(S);
  112. if(S==nullptr){
  113. m*=2;
  114. k=0;
  115. S=solution[step];
  116. }
  117. else{
  118. ++k;
  119. if(k==m) break;
  120. }
  121. }
  122. if(m>max_time_subdivisions){
  123. cerr<<"Max time subdivision reached"<<endl;
  124. scheme_error=1;
  125. }
  126. //cout<<"[spaceSolution] done"<<endl;
  127. }
  128. Solution*
  129. Kernel::Piccard(Solution* Sin){
  130. //Return a valid solution or nullptr if not converge
  131. //cout<<"[Kernel::Piccard]"<<endl;
  132. memcpy(Sin.l,Sin.hsat,sizeof(double)*geometry.nX);
  133. //Compute Pl with l=hsat of input solution and P=pressure of input_solution
  134. Solution* Spl=pool_solutions.pop();
  135. compute_Pl(*Spl,Sin.hsat,Sin.P);
  136. double dt=Time::dT/m; // util ????
  137. size_t count=0;
  138. //Specicy to compute Richards on all columns
  139. for(size_t i=0;i<geometry.nX;++i) indice_x_Richards[i]=true;
  140. double error=0;
  141. Solution* Snew=allVerticalRichards(Sin,Sin,Spl);
  142. if(Snew==nullptr) return false; //allVerti... must compute sol_out.P and sol_out.hsat
  143. //cout<<"[Piccard] done"<<endl;
  144. //Quitte de facon anticipe
  145. return true;
  146. compute_l(Snew,error);
  147. compute_Pl(Snew,Snew.l,Snew.P);
  148. if(!horizontalProblem(Sin,Snew,error)) return false; //Set hydr of Snew voir mettre hydr_in
  149. if(!overlandProblem(Sin,Sin,Snew,error)) return false; //Set hov of Snew
  150. //Comput error
  151. double error_prev=error;
  152. while(error>=tolerence_Piccard and count<max_iterations_Piccard and (abs(error_prev-error)>tolerence_Piccard/100 or error<oscilation_Piccard)){
  153. Solution* Sold=Snew;
  154. error_prev=error;
  155. ++count;
  156. error=0;
  157. Snew=allVerticalRichards(Sin,Sold,Sold);
  158. if(Snew==nullptr) return false;
  159. compute_l(Snew,error);
  160. compute_Pl(Snew,Snew.l,Snew.P);
  161. if(!horizontalProblem(Sold,Snew,error)) return false;
  162. if(!overlandProblem(Sin,Sold,Snew,error)) return false;
  163. }
  164. compute_mass(Snew);
  165. Snew.nstep_Piccard=count;
  166. //cout<<"[Piccard] done"<<endl;
  167. if(error>=tolerence_Piccard){
  168. return nullptr;
  169. //Faire attention à la pile -> rempiler des solutions
  170. }
  171. return Snew;
  172. }
  173. void
  174. Kernel::compute_l(Solution& S,double& error) {
  175. //Update S.l using S.hsat
  176. bool e=0;
  177. for(size_t ix=0;ix<geometry.nX;++ix){
  178. double a=S.l[ix];
  179. double b=max(S.hsat[ix],a);
  180. S.l[ix]=b;
  181. double t=b-a;
  182. e+=t*t;
  183. }
  184. error+=sqrt(e);
  185. }
  186. void
  187. Kernel::compute_Pl(Solution& S,const double* h,double** P){
  188. //cout<<"[Kernel::compute_Pl]"<<endl;
  189. for(size_t ix=0;ix<geometry.nX;++ix){
  190. double* Px=P[ix];
  191. if(h[ix]==geometry.hsoil[ix]){
  192. S.Pl[ix]=Px[geometry.nZ[ix]-1];
  193. //if(S.Pl[ix]!=-2000) cout<<"error "<<ix<<endl;
  194. }
  195. else{
  196. size_t a=(h[ix]-geometry.hbot[ix])/geometry.dZ[ix];
  197. double p1=Px[a];
  198. double p2=Px[a+1];
  199. S.Pl[ix]=p1+(p2-p1)/geometry.dZ[ix]*(h[ix]-geometry.Z[ix][a]);
  200. //cout<<ix<<" : "<<S.Pl[ix]<<endl;
  201. }
  202. }
  203. }
  204. bool
  205. Kernel::allVerticalRichards(Solution& S_0,Solution& S_s,Solution& S_sp){
  206. //cout<<"[Kernel::allVerticalRichards]"<<endl;
  207. for(size_t ix=0;ix<geometry.nX;++ix){
  208. if(indice_x_Richards[ix]){
  209. if(!Richards1dEvolutiveTime(ix,S_0,S_s,S_sp)) return false;
  210. }
  211. }
  212. //cout<<"[Kernel::allVerticalRichards] done"<<endl;
  213. return true;
  214. }
  215. bool
  216. Kernel::Richards1dEvolutiveTime(size_t ix,const Solution& S_0,const Solution& S_s,Solution& S_sp){
  217. //cout<<"[Kernel::Richards1dEvolutiveTime]"<<endl;
  218. //cout<<" ix = "<<ix<<endl;
  219. //Warning flux_bot and div_w are always zero
  220. double flux_bot=bottomFluxRichards(ix,S_s);
  221. compute_div_w(ix,S_s);
  222. size_t q=1;
  223. size_t l=0;
  224. bool conv;
  225. //cout<<"Time::dT "<<Time::dT<<endl;
  226. double dt=Time::dT/m*3600; //in second
  227. while(l<q and q<=max_Richards_time_subdivisions){
  228. //cout<<" l,q = "<<l<<','<<q<<endl;
  229. if(l=0){
  230. conv=Richards1d(ix,S_0,S_s,S_sp,dt,flux_bot);
  231. }
  232. else{
  233. conv=Richards1d(ix,S_0,S_sp,S_sp,dt,flux_bot);
  234. }
  235. if(!conv){
  236. q*=2;
  237. dt/=2;
  238. l=0;
  239. }
  240. else{
  241. ++l;
  242. }
  243. }
  244. //{cout<<"Continue ?"<<endl;char a;cin>>a;}
  245. if(q>max_Richards_time_subdivisions) return false;
  246. return true;
  247. }
  248. void
  249. Kernel::compute_mass(Solution& S){
  250. }
  251. bool
  252. Kernel::horizontalProblem(Solution& S,double& error){
  253. //Compute hydr from P, l, Pl, sources, time
  254. //return error otherwise
  255. return true;
  256. }
  257. bool
  258. Kernel::overlandProblem(const Solution& S_in,Solution& S_out,double& error){
  259. //Compute hov
  260. //return error otherwise
  261. return true;
  262. }
  263. void
  264. Kernel::saturationInterface(const Solution& S_in,Solution& S_out){
  265. /* Solution& S_in=*solution[sol_in];
  266. Solution& S_out=*solution[sol_out];
  267. for(size_t ix=0;ix<geometry.nX;++ix){
  268. double* Px_in=S_in.P[ix];
  269. size_t iz=0;
  270. for(;iz<geometry.nZ[ix] and Px_in[iz]>Psat;++iz);
  271. if(iz>0 and Px_in[iz]<=Psat){
  272. S_out.hsat[ix]=(Psat-Px_in[iz-1])*geometry.dZ[ix]/(Px_in[iz]-Px_in[iz-1])+geometry.Z[ix][iz-1];
  273. }
  274. else{
  275. S_out.hsat[ix]=(iz==0)?geometry.hbot[ix]:geometry.hsoil[ix];
  276. }
  277. }*/
  278. }
  279. double
  280. Kernel::bottomFluxRichards(size_t ix,const Solution& S){
  281. return 0;
  282. }
  283. void
  284. Kernel::compute_div_w(size_t ix,const Solution& S){
  285. double* div_w_ix=div_w[ix];
  286. for(size_t iz=0;iz<geometry.nZ[ix];++iz){
  287. div_w_ix[iz]=0;
  288. }
  289. }
  290. bool
  291. Kernel::Richards1d(size_t ix,const Solution& S_0,const Solution& S_s,Solution& S_sp,double dt,double flux_bot){
  292. //cout<<"[Richards1d]"<<endl;
  293. size_t nZ=geometry.nZ[ix];
  294. double* P0=S_0.P[ix];
  295. double* Ps=S_s.P[ix];
  296. double* Psp=S_sp.P[ix];
  297. double n_P0=norm2(P0,nZ);
  298. if(weightedRichards1d(ix,P0,Ps,Psp,dt,flux_bot,1,n_P0)) return true;
  299. return weightedRichards1d(ix,P0,Ps,Psp,dt,flux_bot,0.5,n_P0);
  300. }
  301. bool
  302. Kernel::weightedRichards1d(size_t ix,double* P0,double* Ps,double* Psp,double dt,double flux_bot,double r,double n_P0){
  303. // cout<<"[weightedRichards1d]"<<endl;
  304. //cout<<"r = "<<r<<endl;
  305. //cout<<"ix = "<<ix<<endl;
  306. size_t nZ=geometry.nZ[ix];
  307. double n0=norm2(P0,nZ);
  308. double* Pi=Ps;
  309. double* Po=P_temp[ix];
  310. size_t count=0;
  311. double e=+inf;
  312. while(e>=tolerence_Richards and count<max_iterations_Richards){
  313. ++count;
  314. solveSystemRichards(ix,P0,Pi,Po,flux_bot,dt,count);
  315. e=error2(Pi,Po,nZ)/n0;
  316. //cout<<count<<" : "<<e<<" vs "<<tolerence_Richards<<endl;
  317. if(count==1){
  318. Pi=Po;
  319. Po=Psp;
  320. }
  321. else{
  322. swap(Pi,Po);
  323. }
  324. }
  325. if(e<tolerence_Richards){
  326. //cout<<"[converge]"<<endl;
  327. memcpy(Psp,Pi,nZ*sizeof(double));
  328. return true;
  329. }
  330. //cout<<"[don't converge]"<<endl;
  331. return false;
  332. }
  333. void
  334. Kernel::solveSystemRichards(size_t ix,double* P0,double* P,double* Pout,double flux_bot,double dt,size_t count){
  335. //TODO treat fpump
  336. /*cout<<"[solveSystemRichards]"<<endl;
  337. cout<<"P0 = "<<P0<<endl;
  338. cout<<"Pin = "<<P<<endl;
  339. cout<<"Pout = "<<Pout<<endl;*/
  340. size_t nZ=geometry.nZ[ix];
  341. assert(nZ>=3);
  342. double dZ=geometry.dZ[ix];
  343. double* sup_A=t_sup_A[ix];
  344. double* diag_A=t_diag_A[ix];
  345. double* sub_A=t_sub_A[ix];
  346. double* sup_B=t_sup_B[ix];
  347. double* diag_B=t_diag_B[ix];
  348. double* sub_B=t_sub_B[ix];
  349. double* sup_C=t_sup_C[ix];
  350. double* diag_C=t_diag_C[ix];
  351. double* sub_C=t_sub_C[ix];
  352. double* F=t_F[ix];
  353. double* G=t_G[ix];
  354. double* S=t_S[ix];
  355. double* H=t_H[ix];
  356. double* R=t_R[ix];
  357. double* I=t_I[ix];
  358. double* BB=t_BB[ix];
  359. //Compute A
  360. diag_A[0]=(Physics::phi*dZ*Physics::ds(P[0]))/(2*dt);
  361. for(size_t i=1;i<nZ-1;++i){
  362. diag_A[i]=(Physics::phi*dZ*Physics::ds(P[i]))/dt;
  363. }
  364. //Compute B
  365. //TODO : A optimiser boucle par rapport aux appels de Kr
  366. double alpha=Physics::k0/(2*Physics::rho*Physics::g*dZ);
  367. diag_B[0]=alpha*(Physics::kr(P[0])+Physics::kr(P[1]));
  368. sup_B[0]=-diag_B[0];
  369. diag_B[nZ-2]=alpha*(Physics::kr(P[nZ-3])+2*Physics::kr(P[nZ-2])+Physics::kr(P[nZ-1]));
  370. sub_B[nZ-3]=-alpha*(Physics::kr(P[nZ-3])+Physics::kr(P[nZ-2]));
  371. for(size_t i=1;i<nZ-2;++i){
  372. diag_B[i]=alpha*(Physics::kr(P[i-1])+2*Physics::kr(P[i])+Physics::kr(P[i+1]));
  373. sub_B[i-1]=-alpha*(Physics::kr(P[i-1])+Physics::kr(P[i]));
  374. sup_B[i]=-alpha*(Physics::kr(P[i])+Physics::kr(P[i+1]));
  375. }
  376. //Compute C
  377. double hk=Physics::k0/2;
  378. double temp=1/(dZ*Physics::rho*Physics::g);
  379. diag_C[0]=-hk*Physics::dkr(P[0])*(temp*(P[1]-P[0])+1);
  380. sup_C[0]=-hk*Physics::dkr(P[1])*(temp*(P[1]-P[0])+1);
  381. diag_C[nZ-2]=hk*Physics::dkr(P[nZ-3])*temp*(-P[nZ-3]+2*P[nZ-2]-P[nZ-1]);
  382. sub_C[nZ-3]=hk*Physics::dkr(P[nZ-3])*(temp*(P[nZ-2]-P[nZ-3])+1);
  383. for(size_t i=1;i<nZ-2;++i){
  384. diag_C[i]=hk*Physics::dkr(P[i])*temp*(-P[i-1]+2*P[i]-P[i+1]);
  385. sub_C[i-1]=hk*Physics::dkr(P[i-1])*(temp*(P[i]-P[i-1])+1);
  386. sup_C[i]=-hk*Physics::dkr(P[i+1])*(temp*(P[i+1]-P[i])+1);
  387. }
  388. //Compute G
  389. clear(G,nZ-1);
  390. G[nZ-2]=-alpha*(Physics::kr(P[nZ-2])+Physics::kr(P[nZ-1]))*P[nZ-1];
  391. //Compute S
  392. S[0]=-hk*(Physics::kr(P[0])+Physics::kr(P[1]));
  393. for(size_t i=1;i<nZ-1;++i){
  394. S[i]=hk*(Physics::kr(P[i-1])-Physics::kr(P[i+1]));
  395. }
  396. //Compute H
  397. clear(H,nZ-1);
  398. H[nZ-2]=-hk*Physics::dkr(P[nZ-1])*(temp*(P[nZ-1]-P[nZ-2])+1);
  399. //Compute R
  400. clear(R,nZ-1);
  401. R[0]=-flux_bot;
  402. //Compute I
  403. I[0]=(Physics::phi*dZ*(Physics::s(P[0])-Physics::s(P0[0])))/(2*dt);
  404. for(size_t i=1;i<nZ-1;++i){
  405. I[i]=(Physics::phi*dZ*(Physics::s(P[i])-Physics::s(P0[i])))/dt;
  406. }
  407. //Compute BB
  408. clear(BB,nZ-1);
  409. //TODO : Add BB computation from fpump
  410. //Compute F
  411. F[0]=div_w[ix][0]*dZ+R[0]-G[0]-I[0]-S[0]-H[0]+(diag_A[0]+diag_C[0])*P[0]+sup_C[0]*P[1];
  412. for(size_t i=1;i<nZ-2;++i){
  413. F[i]=div_w[ix][i]*dZ+R[i]-G[i]-I[i]-S[i]-H[i]+(diag_A[i]+diag_C[i])*P[i]+sub_C[i-1]*P[i-1]+sup_C[i]*P[i+1];
  414. }
  415. F[nZ-2]=div_w[ix][nZ-2]*dZ+R[nZ-2]-G[nZ-2]-I[nZ-2]-S[nZ-2]-H[nZ-2]+(diag_A[nZ-2]+diag_C[nZ-2])*P[nZ-2]+sub_C[nZ-3]*P[nZ-3];
  416. // / if(ix==39) display("F",F,nZ-1);
  417. //TODO Add contribution of BB in F
  418. for(size_t i=0;i<nZ-2;++i){
  419. sub_A[i]=(sub_B[i]+sub_C[i]);
  420. diag_A[i]+=(diag_B[i]+diag_C[i]);
  421. sup_A[i]=(sup_B[i]+sup_C[i]);
  422. }
  423. diag_A[nZ-2]+=(diag_B[nZ-2]+diag_C[nZ-2]);
  424. Thomas(nZ-1,sub_A,diag_A,sup_A,F,Pout);
  425. Pout[nZ-1]=P[nZ-1];
  426. }