Changeset 26236
- Timestamp:
- 05/04/21 10:09:14 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk-jpl/src/c/cores/love_core.cpp
r25912 r26236 9 9 #include "../modules/modules.h" 10 10 #include "../solutionsequences/solutionsequences.h" 11 void love_core(FemModel* femmodel){ 12 13 Vector<IssmDouble> *wg = NULL; 14 Vector<IssmDouble> *dwdtg = NULL; 15 IssmDouble *x = NULL; 16 IssmDouble *y = NULL; 11 #include "petscblaslapack.h" 12 13 14 void love_init(FemModel* femmodel, Matlitho* matlitho){/*{{{*/ 15 // initialize Planet_Mass(r) for efficient computation of gravity, value of surface gravity and inital size of the yi equation system 16 bool verbosemod = (int)VerboseModule(); 17 18 int numlayers = matlitho->numlayers; 19 IssmDouble* r=matlitho->radius; 20 IssmDouble* EarthMass=xNewZeroInit<IssmDouble>(numlayers+1); 21 IssmDouble r1,r2,ro, GG; 22 femmodel->parameters->FindParam(&GG,LoveGravitationalConstantEnum); 23 24 for (int i=0;i<numlayers;i++){ 25 r2 = r[i+1]; 26 ro = matlitho->density[i]; 27 if (i==0){ 28 EarthMass[i] = ro*pow(r2,3.0)*4.0*PI/3.0; 29 }else{ 30 r1=r[i]; 31 EarthMass[i] = EarthMass[i-1] + ro*(pow(r2,3.0)-pow(r1,3.0))*4.0*PI/3.0;; 32 } 33 } 34 35 IssmDouble g0=EarthMass[numlayers-1]*GG/pow(r[numlayers],2.0); 36 femmodel->parameters->SetParam(g0,LoveG0Enum); 37 femmodel->parameters->SetParam(EarthMass,numlayers,LoveEarthMassEnum); 38 xDelete<IssmDouble>(EarthMass); 39 40 int nyi=6*(numlayers+1); 41 int starting_layer=0; 42 femmodel->parameters->SetParam(nyi,LoveNYiEquationsEnum); 43 femmodel->parameters->SetParam(starting_layer,LoveStartingLayerEnum); 44 } 45 46 void GetEarthRheology(IssmDouble* pla, IssmDouble* pmu, int layer_index, IssmDouble omega,FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 47 48 //returns lame parameters (material rigity) lambda and mu for the right frequency and layer 49 IssmDouble vi=matlitho->viscosity[layer_index]; 50 IssmDouble mu=matlitho->lame_mu[layer_index]; 51 IssmDouble la=matlitho->lame_lambda[layer_index]; 52 int rheo=matlitho->rheologymodel[layer_index]; 53 54 if (vi!=0 && omega!=0.0){ //take into account viscosity in the rigidity if the material isn't a perfect fluid 55 //Otherwise return the elastic value 56 IssmDouble ka=la + 2.0/3.0*mu; //Bulk modulus 57 if (rheo==2){//EBM 58 IssmDouble alpha=matlitho->ebm_alpha[layer_index]; 59 IssmDouble delta=matlitho->ebm_delta[layer_index]; 60 IssmDouble taul=matlitho->ebm_taul[layer_index]; 61 IssmDouble tauh=matlitho->ebm_tauh[layer_index]; 62 IssmDouble hf1,hf2,U1,U2; 63 IssmDouble* a=xNew<IssmDouble>(2); 64 IssmDouble* b=xNew<IssmDouble>(1); 65 66 a[0]=1.0;a[1]=1.0+alpha/2.0; 67 b[0]=2.0+alpha/2.0; 68 //hf1=HypergeometricFunctionx(a, b, 2, 1, -pow(omega*tauh,2.0), 0, 0, 15); 69 //hf2=HypergeometricFunctionx(a, b, 2, 1, -pow(omega*taul,2.0), 0, 0, 15); 70 //hf1=hypergeometric_pFq({a[0], a[1]}, {b[0]},-pow(omega*tauh,2.0)); 71 //hf2=hypergeometric_pFq_({a[0], a[1]}, {b[0]},-pow(omega*taul,2.0)); 72 U1=(pow(tauh,alpha)-pow(taul,alpha))/alpha-pow(omega,2.0)/(2.0+alpha)*(pow(tauh,2.0+alpha)*hf1-pow(taul,2.0+alpha)*hf2); 73 74 a[0]=1.0;a[1]=.5+alpha/2.0; 75 b[0]=1.5+alpha/2.0; 76 //hf1=HypergeometricFunctionx(a, b, 2, 1, -pow(omega*tauh,2.0), 0, 0, 15); 77 //hf2=HypergeometricFunctionx(a, b, 2, 1, -pow(omega*taul,2.0), 0, 0, 15); 78 //hf1=hypergeometric_pFq({a[0], a[1]}, {b[0]},-pow(omega*tauh,2.0)); 79 //hf2=hypergeometric_pFq({a[0], a[1]}, {b[0]},-pow(omega*taul,2.0)); 80 U2=(pow(tauh,1.0+alpha)*hf1-pow(taul,1.0+alpha)*hf2)/(1.0+alpha); 81 82 mu=mu/(1.0+ alpha*delta/(pow(tauh,alpha)-pow(taul,alpha))*(U1 + omega*U2) -mu/vi/omega); 83 la=ka-2.0/3.0*mu; 84 85 xDelete<IssmDouble>(a); 86 xDelete<IssmDouble>(b); 87 } 88 else if (rheo==1){//Burgers 89 IssmDouble vi2=matlitho->burgers_viscosity[layer_index]; 90 IssmDouble mu2=matlitho->burgers_mu[layer_index]; 91 92 mu=mu*omega*(omega+mu2/vi2)/((omega+mu2/vi2)*(omega+mu/vi)+mu/vi2*omega); 93 la=ka-2.0/3.0*mu; 94 } 95 else{//Maxwell 96 la = (la + mu*ka/vi/omega)/(1.0 + mu/vi/omega); 97 mu = mu/(1.0+mu/vi/omega); 98 } 99 } 100 101 *pla=la; 102 *pmu=mu; 103 104 } /*}}}*/ 105 106 107 IssmDouble GetGravity(IssmDouble r2, int layer_index, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 108 //computes gravity at radius r2 109 IssmDouble* EarthMass; 110 IssmDouble g, GG; 111 112 femmodel->parameters->FindParam(&EarthMass,&matlitho->numlayers,LoveEarthMassEnum); 113 femmodel->parameters->FindParam(&GG,LoveGravitationalConstantEnum); 114 IssmDouble ro=matlitho->density[layer_index]; 115 IssmDouble M=0; 116 IssmDouble r1=0; 117 if (layer_index==0){ 118 M=4.0/3.0*PI*ro*pow(r2,3.0); 119 } 120 else{ 121 r1=matlitho->radius[layer_index]; 122 M=EarthMass[layer_index-1]+4.0/3.0*PI*ro*(pow(r2,3.0)-pow(r1,3.0)); 123 } 124 return g= GG*M/pow(r2,2.0); 125 }/*}}}*/ 126 127 void fill_yi_prefactor(IssmDouble* yi_prefactor, int* pdeg, IssmDouble* pomega, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 128 //precalculates partial derivative factors for function yi_derivatives 129 IssmDouble ra=matlitho->radius[matlitho->numlayers]; 130 IssmDouble g0,r0,mu0, GG; 131 int nstep,nindex, starting_layer; 132 femmodel->parameters->FindParam(&g0,LoveG0Enum); 133 femmodel->parameters->FindParam(&r0,LoveR0Enum); 134 femmodel->parameters->FindParam(&mu0,LoveMu0Enum); 135 femmodel->parameters->FindParam(&GG,LoveGravitationalConstantEnum); 136 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 137 femmodel->parameters->FindParam(&starting_layer,LoveStartingLayerEnum); 138 139 IssmDouble frh,frhg0,fgr0,fgr,fn,rm0,rlm,flm; 140 IssmDouble xmin,xmax,x,dr; 141 IssmDouble g,ro, issolid; 142 143 if (pomega) { //frequency and degree dependent terms /*{{{*/ 144 IssmDouble la,mu; 145 IssmDouble* f=xNewZeroInit<IssmDouble>(12); 146 int deg=*pdeg; 147 IssmDouble omega=*pomega; 148 fn=deg*(deg+1.0); 149 150 for (int layer_index=starting_layer;layer_index<matlitho->numlayers;layer_index++){ 151 152 ro=matlitho->density[layer_index]; 153 issolid=matlitho->issolid[layer_index]; 154 if(issolid==1){ 155 GetEarthRheology(&la, &mu,layer_index,omega,femmodel,matlitho); 156 157 /*_______Expressions*/ 158 flm=(la+2.0*mu); 159 rlm=(3.0*la+2.0*mu)/(la+2.0*mu); 160 rm0=mu/mu0; 161 frh=ro*ra/mu0; 162 163 f[0]=(-2.0*la/flm); 164 f[1]=mu0/flm; 165 f[2]=(la*fn/flm); 166 f[3]=rm0*rlm; 167 f[4]=ro*pow(omega,2.0)*ra/mu0; 168 f[5]=(-4.0*mu/flm); 169 f[6]=fn*frh; 170 f[7]=-(2.0*rm0*rlm)*fn; 171 f[8]=1.0/rm0; 172 f[9]=-2.0*rm0*rlm; 173 f[10]=-la/flm; 174 f[11]=2.0*rm0*(la*(2.0*fn-1.0)+2.0*mu*(fn-1.0))/flm; 175 176 xmin=matlitho->radius[layer_index]/ra; 177 xmax=(matlitho->radius[layer_index+1])/ra; 178 dr = (xmax -xmin)/nstep; 179 x=xmin; 180 for (int n=0;n<nstep;n++){ 181 g=GetGravity(x*ra,layer_index,femmodel,matlitho); 182 183 nindex=layer_index*nstep*36+n*36; 184 yi_prefactor[nindex+ 0*6+0]= f[0]/x; // in dy[0*6+0] 185 yi_prefactor[nindex+ 0*6+1]= f[1]; // in dy[0*6+1] 186 yi_prefactor[nindex+ 0*6+2]= f[2]/x; // in dy[0*6+2] 187 yi_prefactor[nindex+ 1*6+0]= 4.0*(-frh*g+f[3]/x)/x + f[4];// in dy[1*6+0] 188 yi_prefactor[nindex+ 1*6+1]= f[5]/x; // in dy[1*6+1] 189 yi_prefactor[nindex+ 1*6+2]= (f[6]*g+f[7]/x)/x; // in dy[1*6+2] 190 yi_prefactor[nindex+ 2*6+3]= f[8]; // in dy[2*6+3] 191 yi_prefactor[nindex+ 3*6+0]= (frh*g+f[9]/x)/x; // in dy[3*6+0] 192 yi_prefactor[nindex+ 3*6+1]= f[10]/x; // in dy[3*6+1] 193 yi_prefactor[nindex+ 3*6+2]= f[11]/(x*x) + f[4]; // in dy[3*6+2] 194 x=x+dr; 195 } 196 } 197 } 198 199 xDelete<IssmDouble>(f); 200 /*}}}*/ 201 } else if (pdeg) { // degree dependent terms /*{{{*/ 202 int deg=*pdeg; 203 fn=(deg*(deg+1.0)); 204 205 for (int layer_index=starting_layer;layer_index<matlitho->numlayers;layer_index++){ 206 ro=matlitho->density[layer_index]; 207 issolid=matlitho->issolid[layer_index]; 208 209 /*_______Expressions*/ 210 fgr=4.0*PI*GG*ro*ra; 211 212 xmin=matlitho->radius[layer_index]/ra; 213 xmax=(matlitho->radius[layer_index+1])/ra; 214 dr = (xmax -xmin)/nstep; 215 x=xmin; 216 for (int n=0;n<nstep;n++){ 217 nindex=layer_index*nstep*36+n*36; 218 g=GetGravity(x*ra,layer_index,femmodel,matlitho); 219 220 if(issolid==1){ 221 yi_prefactor[nindex+ 1*6+3]= fn/x; // in dy[1*6+3] 222 yi_prefactor[nindex+ 5*6+2]= -(fgr/g0*fn)/x; // in dy[5*6+2] 223 yi_prefactor[nindex+ 5*6+4]= fn/(x*x); // in dy[5*6+4] 224 } else { 225 yi_prefactor[nindex+ 1*6+0]= (-4.0*(fgr/g)+fn/x)/x; // in dy[1*6+0] liquid layer 226 } 227 x=x+dr; 228 } 229 } 230 /*}}}*/ 231 } else { // static terms /*{{{*/ 232 for (int layer_index=starting_layer;layer_index<matlitho->numlayers;layer_index++){ 233 ro=matlitho->density[layer_index]; 234 issolid=matlitho->issolid[layer_index]; 235 236 /*_______Expressions*/ 237 frhg0=ro*g0*ra/mu0; 238 fgr=4.0*PI*GG*ro*ra; 239 240 xmin=matlitho->radius[layer_index]/ra; 241 xmax=(matlitho->radius[layer_index+1])/ra; 242 dr = (xmax -xmin)/nstep; 243 x=xmin; 244 for (int n=0;n<nstep;n++){ 245 g=GetGravity(x*ra,layer_index,femmodel,matlitho); 246 nindex=layer_index*nstep*36+n*36; 247 if(issolid==1){ 248 yi_prefactor[nindex+ 1*6+5]= -frhg0; // in dy[1*6+5] 249 yi_prefactor[nindex+ 2*6+0]= -1.0/x; // in dy[2*6+0] 250 yi_prefactor[nindex+ 2*6+2]= 1.0/x; // in dy[2*6+2] 251 yi_prefactor[nindex+ 3*6+3]= -3.0/x; // in dy[3*6+3] 252 yi_prefactor[nindex+ 3*6+4]= -frhg0/x; // in dy[3*6+4] 253 yi_prefactor[nindex+ 4*6+0]= fgr/g0; // in dy[4*6+0] 254 yi_prefactor[nindex+ 4*6+5]= 1.0; // in dy[4*6+5] 255 yi_prefactor[nindex+ 5*6+5]= -2.0/x; // in dy[5*6+5] 256 } else { 257 yi_prefactor[nindex+ 0*6+0]= fgr/g; // in dy[0*6+0] liquid layer 258 yi_prefactor[nindex+ 0*6+1]= 1.0; // in dy[0*6+1] liquid layer 259 yi_prefactor[nindex+ 1*6+1]= -2.0/x-fgr/g; // in dy[1*6+1] liquid layer 260 } 261 x=x+dr; 262 } 263 } 264 /*}}}*/ 265 } 266 }/*}}}*/ 267 268 IssmDouble* yi_derivatives(IssmDouble* y, int layer_index, int n, IssmDouble* yi_prefactor, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 269 //computes yi derivatives at r=radius[layer_index]+ n/nstep*(radius[layer_index+1]-radius[layer_index]) 270 271 IssmDouble issolid=matlitho->issolid[layer_index]; 272 int iy,id,ny, nindex, nstep; 273 IssmDouble* dydx=xNewZeroInit<IssmDouble>(6); 274 IssmDouble* dy=xNewZeroInit<IssmDouble>(36); 275 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 276 277 /*{{{*/ /* For reference: 278 flm=(la+2.0*mu); 279 rlm=(3.0*la+2.0*mu)/(la+2.0*mu); 280 rm0=mu/mu0; 281 rg0=g/g0; 282 frh=ro*g*ra/mu0; 283 fgr=4.0*PI*GG*ro*ra/g0; 284 fn=(deg*(deg+1.0)); 285 286 287 if(issolid==1){ 288 ny = 6; 289 290 dy[0*6+0]= (-2.0*la/flm)/x; 291 dy[0*6+1]= mu0/flm; 292 dy[0*6+2]= (la*fn/flm)/x; 293 dy[0*6+3]= 0.0; 294 dy[0*6+4]= 0.0; 295 dy[0*6+5]= 0.0; 296 297 dy[1*6+0]= 4.0*(-frh+rm0*rlm/x)/x + ro*pow(omega,2.0)*ra/mu0; 298 dy[1*6+1]=(-4.0*mu/flm)/x; 299 dy[1*6+2]= fn*(frh-2.0*rm0*rlm/x)/x; 300 dy[1*6+3]= fn/x; 301 dy[1*6+4]= 0.0; 302 dy[1*6+5]= -frh/rg0; 303 304 dy[2*6+0]= -1.0/x; 305 dy[2*6+1]= 0.0; 306 dy[2*6+2]= 1.0/x; 307 dy[2*6+3]= 1/rm0; 308 dy[2*6+4]= 0.0; 309 dy[2*6+5]= 0.0; 310 311 dy[3*6+0]= (frh-2.0*rm0*rlm/x)/x; 312 dy[3*6+1]= ( -la/flm)/x; 313 dy[3*6+2]= (2.0*rm0*(la*(2.0*fn-1.0)+2.0*mu*(fn-1.0))/flm)/(x*x) + ro*pow(omega,2.0)*ra/mu0; 314 dy[3*6+3]= -3.0/x; 315 dy[3*6+4]= -(frh/rg0)/x; 316 dy[3*6+5]= 0.0; 317 318 dy[4*6+0]= fgr; 319 dy[4*6+1]= 0.0; 320 dy[4*6+2]= 0.0; 321 dy[4*6+3]= 0.0; 322 dy[4*6+4]= 0.0; 323 dy[4*6+5]= 1.0; 324 325 dy[5*6+0]= 0.0; 326 dy[5*6+1]= 0.0; 327 dy[5*6+2]= -(fgr*fn)/x; 328 dy[5*6+3]= 0.0; 329 dy[5*6+4]= fn/(x*x); 330 dy[5*6+5]= -2.0/x; 331 332 } else { 333 ny = 2; 334 335 dy[0*6+0]= fgr/rg0; 336 dy[0*6+1]= 1.0; 337 dy[1*6+0]= (-4.0*(fgr/rg0)+fn/x)/x; 338 dy[1*6+1]= -2.0/x-fgr/rg0; 339 } 340 */ /*}}}*/ 341 342 if(issolid==1){ 343 ny = 6; 344 } else { 345 ny = 2; 346 } 347 348 for (id=0;id<ny;id++){ 349 for (iy=0;iy<ny;iy++){ 350 nindex=layer_index*nstep*36+n*36; 351 dydx[id]=dydx[id]+yi_prefactor[nindex+id*6+iy]*y[iy]; 352 } 353 } 354 xDelete<IssmDouble>(dy); 355 return dydx; 356 }/*}}}*/ 357 358 void propagate_yi_euler(IssmDouble* y, IssmDouble xmin, IssmDouble xmax, int layer_index, IssmDouble* yi_prefactor, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 359 //yields this: if we have y[j]=1.0 and y[!j]=0.0 at the bottom of the layer, what is y at the top of the layer? 360 //euler method 361 int nstep; 362 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 363 364 IssmDouble* dydx=xNewZeroInit<IssmDouble>(6); 365 IssmDouble dr = (xmax -xmin)/nstep; 366 IssmDouble x=xmin; 367 for(int i = 0;i<nstep;i++){ 368 dydx=yi_derivatives(y,layer_index, i,yi_prefactor,femmodel,matlitho); 369 for (int j=0;j<6;j++){ 370 y[j]+=dydx[j]*dr; 371 } 372 x = x + dr; 373 } 374 xDelete<IssmDouble>(dydx); 375 }/*}}}*/ 376 377 void propagate_yi_RK2(IssmDouble* y, IssmDouble xmin, IssmDouble xmax, int layer_index, IssmDouble* yi_prefactor, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 378 //yields this: if we have y[j]=1.0 and y[!j]=0.0 at the bottom of the layer, what is y at the top of the layer? 379 //Implements Runge-Kutta 2nd order (midpoint method) 380 int nstep; 381 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 382 383 IssmDouble* k1=xNewZeroInit<IssmDouble>(6); 384 IssmDouble* k2=xNewZeroInit<IssmDouble>(6); 385 IssmDouble* k3=xNewZeroInit<IssmDouble>(6); 386 IssmDouble* k4=xNewZeroInit<IssmDouble>(6); 387 IssmDouble* y1=xNewZeroInit<IssmDouble>(6); 388 IssmDouble* y2=xNewZeroInit<IssmDouble>(6); 389 IssmDouble* y3=xNewZeroInit<IssmDouble>(6); 390 391 IssmDouble dr = (xmax -xmin)/nstep; 392 IssmDouble x=xmin; 393 for(int i = 0;i<nstep/2;i++){ 394 k1=yi_derivatives(y,layer_index, 2*i,yi_prefactor,femmodel,matlitho); 395 for (int j=0;j<6;j++) {y1[j]=y[j]+k1[j]*dr;} 396 k2=yi_derivatives(y1,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 397 398 for (int j=0;j<6;j++){ 399 y[j]+=k2[j]*2.0*dr; 400 } 401 x = x + 2.0*dr; 402 } 403 xDelete<IssmDouble>(k1); 404 xDelete<IssmDouble>(k2); 405 xDelete<IssmDouble>(k3); 406 xDelete<IssmDouble>(k4); 407 xDelete<IssmDouble>(y1); 408 xDelete<IssmDouble>(y2); 409 xDelete<IssmDouble>(y3); 410 }/*}}}*/ 411 412 void propagate_yi_RK4(IssmDouble* y, IssmDouble xmin, IssmDouble xmax, int layer_index, IssmDouble* yi_prefactor, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 413 //yields this: if we have y[j]=1.0 and y[!j]=0.0 at the bottom of the layer, what is y at the top of the layer? 414 //Implements Runge-Kutta 4th order 415 int nstep; 416 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 417 418 IssmDouble* k1=xNewZeroInit<IssmDouble>(6); 419 IssmDouble* k2=xNewZeroInit<IssmDouble>(6); 420 IssmDouble* k3=xNewZeroInit<IssmDouble>(6); 421 IssmDouble* k4=xNewZeroInit<IssmDouble>(6); 422 IssmDouble* y1=xNewZeroInit<IssmDouble>(6); 423 IssmDouble* y2=xNewZeroInit<IssmDouble>(6); 424 IssmDouble* y3=xNewZeroInit<IssmDouble>(6); 425 426 IssmDouble dr = (xmax -xmin)/nstep; 427 IssmDouble x=xmin; 428 for(int i = 0;i<nstep/2-1;i++){ 429 k1=yi_derivatives(y,layer_index, 2*i,yi_prefactor,femmodel,matlitho); 430 for (int j=0;j<6;j++) {y1[j]=y[j]+k1[j]*dr;} 431 k2=yi_derivatives(y1,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 432 for (int j=0;j<6;j++) {y2[j]=y[j]+k2[j]*dr;} 433 k3=yi_derivatives(y2,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 434 for (int j=0;j<6;j++) {y3[j]=y[j]+k3[j]*2.0*dr;} 435 k4=yi_derivatives(y3,layer_index, 2*i+2,yi_prefactor,femmodel,matlitho); 436 437 for (int j=0;j<6;j++){ 438 y[j]+=(k1[j]+2.0*k2[j]+2.0*k3[j]+k4[j])/3.0*dr; 439 } 440 x = x + 2.0*dr; 441 } 442 443 //Last step: we don't know the derivative at xmax, so we will assume the values at xmax-dr 444 int i=nstep/2; 445 k1=yi_derivatives(y,layer_index, 2*i,yi_prefactor,femmodel,matlitho); 446 for (int j=0;j<6;j++) {y1[j]=y[j]+k1[j]*dr;} 447 k2=yi_derivatives(y1,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 448 for (int j=0;j<6;j++) {y2[j]=y[j]+k2[j]*dr;} 449 k3=yi_derivatives(y2,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 450 for (int j=0;j<6;j++) {y3[j]=y[j]+k3[j]*2.0*dr;} 451 k4=yi_derivatives(y3,layer_index, 2*i+1,yi_prefactor,femmodel,matlitho); 452 453 for (int j=0;j<6;j++){ 454 y[j]+=(k1[j]+2.0*k2[j]+2.0*k3[j]+k4[j])/3.0*dr; 455 } 456 457 x = x + 2.0*dr; 458 459 xDelete<IssmDouble>(k1); 460 xDelete<IssmDouble>(k2); 461 xDelete<IssmDouble>(k3); 462 xDelete<IssmDouble>(k4); 463 xDelete<IssmDouble>(y1); 464 xDelete<IssmDouble>(y2); 465 xDelete<IssmDouble>(y3); 466 }/*}}}*/ 467 468 void Innersphere_boundaryconditions(IssmDouble* yi, int layer_index, int deg, IssmDouble omega, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 469 //fills the boundary conditions at the bottom of layer[layer_index] in yi[0:2][0:5] 470 471 IssmDouble r = matlitho->radius[layer_index]; 472 IssmDouble ra=matlitho->radius[matlitho->numlayers]; 473 IssmDouble g0,r0,mu0, GG; 474 int nyi; 475 femmodel->parameters->FindParam(&g0,LoveG0Enum); 476 femmodel->parameters->FindParam(&r0,LoveR0Enum); 477 femmodel->parameters->FindParam(&mu0,LoveMu0Enum); 478 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); 479 femmodel->parameters->FindParam(&GG,LoveGravitationalConstantEnum); 480 IssmDouble ro=matlitho->density[layer_index]; 481 IssmDouble issolid=matlitho->issolid[layer_index]; 482 IssmDouble g=GetGravity(r,layer_index,femmodel,matlitho); 483 IssmDouble la,mu; 484 485 if (layer_index==0){ 486 // radius[0] cannot be 0 for numerical reasons, but below our first interface at radius[0] would in reality be the same material as in the first layer 487 GetEarthRheology(&la, &mu,layer_index,omega,femmodel,matlitho); 488 } else { 489 GetEarthRheology(&la, &mu,layer_index-1,omega,femmodel,matlitho); 490 } 491 492 IssmDouble cst = 4.0*PI*GG*ro; 493 IssmDouble r2=pow(r,2.0); 494 495 yi[0+nyi*0]=1.0*r/ra; 496 yi[0+nyi*1]=1.0/(r*ra); 497 yi[0+nyi*2]=0.0; 498 499 yi[1+nyi*0]=(2.0*mu*(deg-1.0-3.0/deg) + cst/3.0*ro*r2)/mu0; 500 yi[1+nyi*1]=(2.0*mu*(deg-1.0)/r2 + cst/3.0*ro)/mu0; 501 yi[1+nyi*2]=-ro/mu0; 502 503 yi[2+nyi*0]=(deg+3.0)/(deg*(deg+1.0))*r/ra; 504 yi[2+nyi*1]=1.0/(deg*r*ra); 505 yi[2+nyi*2]=0.0; 506 507 yi[3+nyi*0]=2.0*mu*(deg+2.0)/((deg+1.0)*mu0); 508 yi[3+nyi*1]=2.0*mu*(deg-1.0)/(deg*r2*mu0); 509 yi[3+nyi*2]=0.0; 510 511 yi[4+nyi*0]=0.0; 512 yi[4+nyi*1]=0.0; 513 yi[4+nyi*2]=1.0/(g0*ra); 514 515 yi[5+nyi*0]=-cst*r/g0; 516 yi[5+nyi*1]=-cst/(r*g0); 517 yi[5+nyi*2]=deg/(r*g0); 518 }/*}}}*/ 519 520 void build_yi_system(IssmDouble* yi, int deg, IssmDouble omega, IssmDouble* yi_prefactor, FemModel* femmodel, Matlitho* matlitho) { /*{{{*/ 521 522 IssmDouble g0,r0,mu0,x,ro1, GG; 523 int nyi,starting_layer, nstep; 524 femmodel->parameters->FindParam(&g0,LoveG0Enum); 525 femmodel->parameters->FindParam(&r0,LoveR0Enum); 526 femmodel->parameters->FindParam(&mu0,LoveMu0Enum); 527 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); 528 femmodel->parameters->FindParam(&GG,LoveGravitationalConstantEnum); 529 femmodel->parameters->FindParam(&starting_layer,LoveStartingLayerEnum); 530 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 531 532 IssmDouble xmin,xmax,one,ro,g; 533 IssmDouble ra=matlitho->radius[matlitho->numlayers]; 534 535 for (int i=0;i<6*(matlitho->numlayers+1);i++){ 536 for(int j=0;j<6*(matlitho->numlayers+1);j++){ 537 yi[i+6*(matlitho->numlayers+1)*j]=0.0; 538 } 539 } 540 541 int ny,is,ii,jj; 542 IssmDouble ystart[6]; 543 for (int k=0;k<6;k++) ystart[k]=0.0; 544 545 int ici = 0; // Index of current interface 546 for (int i = starting_layer; i<matlitho->numlayers;i++){ 547 548 xmin=matlitho->radius[i]/ra; 549 xmax=(matlitho->radius[i+1])/ra; 550 551 552 if (matlitho->issolid[i]){ 553 ny = 6; 554 is = 0; 555 one= 1.0; 556 } else { 557 ny = 2; 558 is = 4; 559 one= -1.0; 560 } 561 562 563 for (int j = 0;j<ny;j++){ 564 for (int k=0;k<6;k++){ystart[k]=0.0;} 565 ystart[j]= 1.0; 566 567 // Numerical Integration 568 //propagate_yi_euler(&ystart[0], xmin, xmax, i, yi_prefactor,femmodel, matlitho); 569 propagate_yi_RK2(&ystart[0], xmin, xmax, i, yi_prefactor,femmodel, matlitho); 570 //propagate_yi_RK4(&ystart[0], xmin, xmax, i, yi_prefactor,femmodel, matlitho); 571 // Boundary Condition matrix - propagation part 572 ii = 6*(ici+1)+is; 573 jj = 6*(ici+1)+j+is-3; 574 for (int kk=0;kk<ny;kk++){ 575 yi[(ii+kk)+nyi*jj] = ystart[kk]*one; 576 } 577 } 578 579 580 // Boundary Condition matrix - solid regions 581 if (matlitho->issolid[i]){ 582 one = -1.0; 583 if (i>0 & !matlitho->issolid[i-1]) one = 1.0; 584 for (int j=0;j<6;j++){ 585 yi[(j+6*ici)+ nyi*(j+6*ici+3)] = one; 586 } 587 } else { // Boundary Condition matrix - liquid regions 588 ro1=matlitho->density[i]; 589 g=GetGravity(matlitho->radius[i], i, femmodel,matlitho); 590 ii = 6*ici; 591 yi[ii+nyi*(ii+3)] = -1.0; 592 yi[ii+nyi*(ii+4+3)] = -g0/g; 593 yi[(ii+1)+nyi*(ii+3)]=-ro1*g*ra/mu0; 594 yi[(ii+2)+nyi*(ii+1+3)]=-1.0; 595 yi[(ii+5)+nyi*(ii+3)]= 4.0*PI*GG*ro1*ra/g0; 596 yi[(ii+4)+nyi*(ii+4+3)]=-1.0; 597 yi[(ii+5)+nyi*(ii+5+3)]=-1.0; 598 g=GetGravity(matlitho->radius[i+1], i,femmodel,matlitho); 599 ii = 6*(ici+1); 600 yi[ii+nyi*(ii-1)]=-1.0; 601 yi[ii+nyi*(ii+1)]=yi[(ii+4)+nyi*(ii+1)]*g0/g; // yi(17,14) solution integration 1 of z5 CMB 602 yi[ii+nyi*(ii+2)]=yi[(ii+4)+nyi*(ii+2)]*g0/g; // yi(17,15) solution integration 2 of z5 CMB 603 // yi(13,..) y1 CMB 604 yi[(ii+1)+nyi*(ii-1)]=-ro1*g*ra/mu0; 605 yi[(ii+2)+nyi*(ii)]=-1.0; 606 yi[(ii+5)+nyi*(ii-1)]= 4.0*PI*GG*ro1*ra/g0; 607 } 608 ici = ici+1; 609 } 610 611 612 //-- Internal sphere: integration starts here rather than r=0 for numerical reasons 613 Innersphere_boundaryconditions(yi, starting_layer, deg, omega, femmodel, matlitho); 614 615 //-- Surface conditions 616 yi[(nyi-6)+nyi*(nyi-3)]=-1.0; 617 yi[(nyi-4)+nyi*(nyi-2)]=-1.0; 618 yi[(nyi-2)+nyi*(nyi-1)]=-1.0; 619 yi[(nyi-1)+nyi*(nyi-1)]=deg+1.0; 620 621 //-- Degree 1 special case 622 if(deg==1){ 623 for (int i=0;i<nyi;i++){ 624 yi[(nyi-1)+nyi*i]=0.0; 625 } 626 yi[(nyi-1)+nyi*(nyi-1)]=1.0; 627 } 628 }/*}}}*/ 629 630 void yi_boundary_conditions(IssmDouble* yi_righthandside, int deg, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 631 632 IssmDouble g0,r0,mu0,ra,rb,rc; 633 int nyi, forcing_type,icb,cmb; 634 IssmDouble* EarthMass; 635 femmodel->parameters->FindParam(&g0,LoveG0Enum); 636 femmodel->parameters->FindParam(&r0,LoveR0Enum); 637 femmodel->parameters->FindParam(&mu0,LoveMu0Enum); 638 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); 639 femmodel->parameters->FindParam(&forcing_type,LoveForcingTypeEnum); 640 femmodel->parameters->FindParam(&icb,LoveInnerCoreBoundaryEnum); 641 femmodel->parameters->FindParam(&cmb,LoveCoreMantleBoundaryEnum); 642 femmodel->parameters->FindParam(&EarthMass,&matlitho->numlayers,LoveEarthMassEnum); 643 644 // In Case of a Inner Core - Outer Core - Mantle planet and Boundary conditions on these 3 interfaces 645 ra=matlitho->radius[matlitho->numlayers]; 646 rb=0; 647 rc=0; 648 if (forcing_type<=4){ 649 rc=matlitho->radius[icb]; 650 } 651 else if (forcing_type<=8){ 652 rb=matlitho->radius[cmb]; 653 } 654 655 IssmDouble ro_mean=EarthMass[matlitho->numlayers-1]/(4.0/3.0*PI*pow(ra,3.0)); 656 xDelete<IssmDouble>(EarthMass); 657 658 for (int i=0;i<(matlitho->numlayers+1)*6;i++) yi_righthandside[i]=0.0; 659 660 switch (forcing_type) { 661 662 //-- forcings at the Inner Core Boundary 663 case 1: //'ICB --Volumetric Potential' 664 yi_righthandside[6*icb+5]=(deg)/(rc*g0); 665 yi_righthandside[6*icb+4]=1.0/(ra*g0); 666 break; 667 case 2: //'ICB --Pressure' 668 yi_righthandside[6*icb+1]=-ro_mean/mu0; 669 break; 670 case 3://'ICB --Loading' 671 yi_righthandside[6*icb+1]=-ro_mean*(2.0*deg+1.0)/(3.0*mu0)*ra/rc; 672 yi_righthandside[6*icb+5]= (2.0*deg+1.0)/(rc*g0); 673 break; 674 case 4://'ICB --Tangential Traction' 675 yi_righthandside[6*icb+3]= ro_mean/mu0; 676 break; 677 678 //--forcings at the Core Mantle Boundary 679 case 5://'CMB --Volumetric Potential' 680 yi_righthandside[6*cmb+1]=-ro_mean/mu0*ra/rb; 681 yi_righthandside[6*cmb+5]= (2.0*deg+1.0)/(rb*g0); 682 break; 683 case 6://'CMB --Pressure' 684 yi_righthandside[6*cmb+1]=-ro_mean/mu0; 685 break; 686 case 7://'CMB --Loading' 687 yi_righthandside[6*cmb+1]=-ro_mean*(2.0*deg+1.0)/(3.0*mu0)*ra/rb; 688 yi_righthandside[6*cmb+5]= (2.0*deg+1.0)/(rb*g0); 689 break; 690 case 8://'CMB --Tangential Traction' 691 yi_righthandside[6*cmb+3]=-ro_mean/mu0; 692 break; 693 694 //--forcings at the surface 695 case 9://'SURF--Volumetric Potential' 696 if (deg>1) yi_righthandside[nyi-1]=(2.0*deg+1.0)/(ra*g0); 697 break; 698 case 10://'SURF--Pressure' 699 yi_righthandside[nyi-5]=-ro_mean/mu0; 700 break; 701 case 11://'SURF--Loading' 702 yi_righthandside[nyi-5]=-ro_mean*(2.0*deg+1.0)/(3.0*mu0); 703 if (deg>1) yi_righthandside[nyi-1]= (2.0*deg+1.0)/(ra*g0); 704 break; 705 case 12://'SURF--Tangential Traction' 706 yi_righthandside[nyi-3]= ro_mean/mu0; 707 break; 708 default: 709 _error_("love core error: forcing_type not supported yet"); 710 } 711 }/*}}}*/ 712 713 714 void solve_yi_system(IssmDouble* loveh, IssmDouble* lovel, IssmDouble* lovek, int deg, IssmDouble omega, IssmDouble* yi, IssmDouble* rhs, FemModel* femmodel, Matlitho* matlitho){ /*{{{*/ 715 716 IssmDouble g0,r0,mu0,loveratio,underflow_tol; 717 IssmDouble* frequencies; 718 int nyi,starting_layer, dummy; 719 bool allow_layer_deletion; 720 femmodel->parameters->FindParam(&g0,LoveG0Enum); 721 femmodel->parameters->FindParam(&r0,LoveR0Enum); 722 femmodel->parameters->FindParam(&mu0,LoveMu0Enum); 723 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); 724 femmodel->parameters->FindParam(&starting_layer,LoveStartingLayerEnum); 725 femmodel->parameters->FindParam(&allow_layer_deletion,LoveAllowLayerDeletionEnum); 726 femmodel->parameters->FindParam(&underflow_tol,LoveUnderflowTolEnum); 727 femmodel->parameters->FindParam(&frequencies,&dummy,LoveFrequenciesEnum); 728 IssmDouble ra=matlitho->radius[matlitho->numlayers]; 729 bool exit=false; 730 int lda,ldb; 731 732 for(;!exit;){ //cycles of: attempt to solve the yi system, then delete a layer if necessary 733 lda=nyi; 734 ldb=nyi; 735 IssmDouble* yilocal=xNew<IssmDouble>(nyi*nyi); // we will need to redeclare these inside here as nyi changes 736 IssmDouble* rhslocal=xNew<IssmDouble>(nyi); 737 738 //we need to do a local copy of yi,rhs to send them to LAPACK with the appropriate size and to keep the original matrices in case layers are deleted and we need to try again 739 for (int i=0;i<nyi;i++){ 740 rhslocal[i]=rhs[i]; 741 for (int j=0;j<nyi;j++){ 742 yilocal[i+j*nyi]=yi[i+j*nyi]; 743 } 744 } 745 //-- Resolution 746 int* ipiv=xNewZeroInit<int>(nyi); //pivot index vector 747 int info = 0;// error checker 748 int nrhs=1; // number of right hand size columns 749 750 dgesv_(&nyi, &nrhs, yilocal, &lda, ipiv, rhslocal, &ldb, &info); 751 xDelete<int>(ipiv); 752 753 if(VerboseSolution() && info!=0){ 754 _printf0_("love core warning in DGESV : LAPACK linear equation solver couldn't resolve the system"); 755 printf("%s %s %s %s\n", "i","j","yi[i+nyi*j]","rhs[i]"); 756 for (int i=0;i<nyi;i++){ 757 for (int j=0;j<nyi;j++){ 758 printf("%i %i %e %e\n", i,j,yi[i+nyi*j],rhs[i]); 759 } 760 } 761 } 762 763 *loveh = rhslocal[nyi-3]*ra*g0; 764 *lovel = rhslocal[nyi-2]*ra*g0; 765 *lovek = rhslocal[nyi-1]*ra*g0; 766 767 IssmDouble loveh1 = rhslocal[3]; 768 IssmDouble lovel1 = rhslocal[5]; 769 IssmDouble lovek1 = rhslocal[7] - pow(matlitho->radius[starting_layer]/ra,deg)/(g0*ra); 770 771 IssmDouble loveh1s = rhslocal[nyi-3]; 772 IssmDouble lovel1s = rhslocal[nyi-2]; 773 IssmDouble lovek1s = rhslocal[nyi-1] - 1.0/(g0*ra); 774 775 loveratio = abs(loveh1/loveh1s); //ratio of center to surface love numbers, determines if we should remove layers 776 if (abs(lovel1/lovel1s) < loveratio) loveratio = abs(lovel1/lovel1s); 777 if (abs(lovek1/lovek1s) < loveratio) loveratio = abs(lovek1/lovek1s); 778 779 if (!allow_layer_deletion || nyi<=12 || omega!=2.0*PI*frequencies[0]){ //We are not allowed to delete layers, or there is only one layer left. We also don't want to delete layers in the middle of a loop on frequencies, as that can lead to a jump that would compromise the inverse laplace transform. 780 goto save_results; 781 } 782 783 if (loveratio<=underflow_tol || xIsNan(loveratio) || xIsInf(loveratio)){//We need to delete a layer and try again if the ratio between deepest love number to surface love number is too low (risk of underflow) or garbage 784 if(VerboseSolution()){ 785 printf("\n Degree: %i, surface/Depth Love number ratio small: %e\n",deg, loveratio); 786 printf(" Changing the interface where the integration starts\n"); 787 printf(" New start interface: r=%gm\n\n", matlitho->radius[starting_layer+1]); 788 } 789 nyi-=6; 790 starting_layer+=1; 791 femmodel->parameters->SetParam(nyi,LoveNYiEquationsEnum); 792 femmodel->parameters->SetParam(starting_layer,LoveStartingLayerEnum); 793 794 795 for (int i=0;i<nyi;i++){//shift everything down by 1 layer 796 rhs[i]=rhs[i+6]; 797 for (int j=0;j<nyi;j++){ 798 yi[j+i*nyi]=yi[j+6+(i+6)*(nyi+6)]; 799 } 800 } 801 802 Innersphere_boundaryconditions(yi, starting_layer, deg, omega, femmodel, matlitho); //we move the first interface to the new starting layer. yi[0:2,0:5] will be different 803 } else { //we are ready to save the outputs and break the main loop 804 805 save_results: 806 for (int i=0;i<nyi;i++){ 807 rhs[i]=rhslocal[i]; 808 for (int j=0;j<nyi;j++){ 809 yi[j+i*nyi]=yilocal[j+i*nyi]; 810 } 811 } 812 813 //make sure we can't output numbers from deleted layers 814 for (int i=nyi;i<(matlitho->numlayers+1)*6;i++){ 815 rhs[i]=0.0; 816 for (int j=0;j<(matlitho->numlayers+1)*6;j++){ 817 yi[j+i*(matlitho->numlayers+1)*6]=0.0; 818 } 819 } 820 for (int i=0;i<nyi;i++){ 821 for (int j=nyi;j<(matlitho->numlayers+1)*6;j++){ 822 yi[j+i*(matlitho->numlayers+1)*6]=0.0; 823 } 824 } 825 826 exit = true; 827 } 828 xDelete<IssmDouble>(yilocal); 829 xDelete<IssmDouble>(rhslocal); 830 } 831 xDelete<IssmDouble>(frequencies); 832 }/*}}}*/ 833 834 IssmDouble factorial(int n){ /*{{{*/ 835 IssmDouble prod=1; 836 for (int i=2;i<n+1;i++) prod*=i; 837 return prod; 838 }/*}}}*/ 839 840 IssmDouble n_C_r(int n, int r){ /*{{{*/ 841 //n choose r 842 int primes[169] = 843 {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 844 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 845 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 846 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 847 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 848 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 849 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 850 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 851 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 852 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 853 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 854 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 855 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 856 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 857 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 858 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 859 947, 953, 967, 971, 977, 983, 991, 997, 1009}; 860 int num, den; 861 num = 1; 862 den = 1; 863 864 for (int i=0;i<r;i++){ 865 num = num*(n-i); 866 den = den*(i+1); 867 if (i>0) { 868 // Divide out common prime factors 869 for (int k=0;k<169;k++){ //169 is the length of the prime vector here 870 if ( i % primes[k] == 0) { // modulo 871 num = num/primes[k]; 872 den = den/primes[k]; 873 } 874 } 875 } 876 } 877 878 IssmDouble res; 879 return res = num/den; 880 }/*}}}*/ 881 882 883 IssmDouble* postwidder_coef(int NTit){ /*{{{*/ 884 //Coefficients of the Post-Widder method through Saltzer summation for inverse Laplace transform: 885 //The Mth iteration estimate will be: f(t)_M = sum_{k=1:2*M}(xi_[M,k] * f(s_k)) 886 //The method is based on equations (2), (6), (7) in: 887 //Valko PP, Abate J. Comparison of sequence accelerators for the Gaver method of numerical Laplace transform inversion. Computational Mathematics and Applications. (2004) 888 //Note that the coefficients xi lack the factor s=k*log(2)/t. 889 //That is because we are computing the heaviside response of the system rather than its impulse response, 890 //and Laplace_Transform(Heaviside(t).*f(t)) = f(s)/s. So s cancels out in the sum for f(t)_M. 891 892 IssmDouble* xi=xNewZeroInit<IssmDouble>(2*NTit*NTit); 893 int indxi; 894 for (int M=1;M<NTit+1;M++){ 895 for (int k=1;k<2*M+1;k++){ 896 indxi=(M-1)*(2*NTit)+k-1; 897 for (int j=floor((k+1)/2);j<min(k,M)+1;j++){ 898 xi[indxi]+=pow(j,M+1.0)/factorial(M)*n_C_r(M,j)*n_C_r(2*j,j)*n_C_r(j,k-j); 899 } 900 xi[indxi]*=pow(-1.0,k+M)/k; 901 } 902 } 903 return xi; 904 }/*}}}*/ 905 906 void postwidder_transform(IssmDouble* Lovet, IssmDouble* Lovef,int d, int t, int NTit, IssmDouble* xi, FemModel* femmodel){ /*{{{*/ 907 //Computes Lovet for time step t and degree d from the PW coefficients xi and the corresponding 2*NTit frequency samples in Lovef 908 909 int nfreq, indxi, indf; 910 femmodel->parameters->FindParam(&nfreq,LoveNfreqEnum); 911 int nt=nfreq/2/NTit; 912 913 indf=d*nfreq+t*2*NTit; 914 IssmDouble LoveM[NTit]; 915 916 for (int M=1;M<NTit+1;M++){ 917 LoveM[M-1]=0.0; 918 for (int k=1;k<2*M+1;k++){ 919 indxi=(M-1)*(2*NTit)+k-1; 920 LoveM[M-1]+=xi[indxi]*Lovef[indf+k-1]; 921 } 922 923 //Make sure we are not getting into numerical instability 924 //Diverging once: ok, we'll give that the benefit of the doubt, it can be an inflexion point in the convergence series 925 //Diverging twice in a row: we are definitely propagating numerical error: revert to the last stable value and exit 926 if (M>3){ 927 if ( abs(LoveM[M-1]-LoveM[M-2]) > abs(LoveM[M-2]-LoveM[M-3]) && 928 abs(LoveM[M-2]-LoveM[M-3]) > abs(LoveM[M-3]-LoveM[M-4]) ){ 929 Lovet[d*nt+t]=LoveM[M-3]; 930 return; 931 } 932 } 933 } 934 Lovet[d*nt+t]=LoveM[NTit-1]; 935 }/*}}}*/ 936 937 void love_freq_to_temporal(IssmDouble* LoveHt,IssmDouble* LoveLt,IssmDouble* LoveKt,IssmDouble* LoveHf,IssmDouble* LoveLf,IssmDouble* LoveKf, FemModel* femmodel){ /*{{{*/ 938 //Transforms all frequency-dependent love numbers into time-dependent love numbers 939 int nfreq,sh_nmax,sh_nmin,indxi,indf, NTit; 940 IssmDouble meanh,meanl,meank,dh,dl,dk; 941 942 femmodel->parameters->FindParam(&nfreq,LoveNfreqEnum); 943 femmodel->parameters->FindParam(&sh_nmax,LoveShNmaxEnum); 944 femmodel->parameters->FindParam(&sh_nmin,LoveShNminEnum); 945 femmodel->parameters->FindParam(&NTit,LoveNTemporalIterationsEnum); 946 947 int nt=nfreq/2/NTit; 948 IssmDouble* xi=postwidder_coef(NTit); 949 950 for (int d=sh_nmin;d<sh_nmax+1;d++){ 951 for (int t=0;t<nt;t++){ 952 postwidder_transform(LoveHt,LoveHf,d,t,NTit,xi,femmodel); 953 postwidder_transform(LoveLt,LoveLf,d,t,NTit,xi,femmodel); 954 postwidder_transform(LoveKt,LoveKf,d,t,NTit,xi,femmodel); 955 } 956 } 957 xDelete<IssmDouble>(xi); 958 }/*}}}*/ 959 960 961 962 void love_core(FemModel* femmodel){ /*{{{*/ 963 964 /*recover materials parameters: there is only one Matlitho, chase it down the hard way:*/ 965 Matlitho* matlitho=NULL; 966 for (Object* & object: femmodel->materials->objects){ 967 Material* material=xDynamicCast<Material*>(object); 968 if(material->ObjectEnum()==MatlithoEnum){ 969 matlitho=xDynamicCast<Matlitho*>(material); 970 break; 971 } 972 } 973 _assert_(matlitho); 17 974 18 975 /*love parameters: */ 976 int nfreq,nyi,starting_layer,nstep,forcing_type,dummy; 977 int sh_nmin,sh_nmax,kernel_index,deleted_layer_offset; 978 bool allow_layer_deletion,love_kernels, istemporal; 979 bool verbosemod = (int)VerboseModule(); 980 IssmDouble lovek, loveh, lovel, loveratio; 981 IssmDouble g0,r0,mu0, underflow_tol, omega; 19 982 IssmDouble *frequencies = NULL; 20 int nfreq,dummy;21 int sh_nmin,sh_nmax;22 IssmDouble g0,r0,mu0;23 bool allow_layer_deletion;24 bool love_kernels;25 int forcing_type;26 bool verbosemod = (int)VerboseModule();27 983 28 984 /*parameters: */ … … 35 991 36 992 /*recover love number parameters: */ 993 37 994 femmodel->parameters->FindParam(&nfreq,LoveNfreqEnum); 38 995 femmodel->parameters->FindParam(&frequencies,&dummy,LoveFrequenciesEnum); _assert_(nfreq==dummy); … … 45 1002 femmodel->parameters->FindParam(&love_kernels,LoveKernelsEnum); 46 1003 femmodel->parameters->FindParam(&forcing_type,LoveForcingTypeEnum); 47 48 /*recover materials parameters: there is only one Matlitho, chase it down the hard way:*/ 49 Matlitho* matlitho=NULL; 50 for (Object* & object: femmodel->materials->objects){ 51 Material* material=xDynamicCast<Material*>(object); 52 if(material->ObjectEnum()==MatlithoEnum){ 53 matlitho=xDynamicCast<Matlitho*>(material); 54 break; 55 } 56 } 57 _assert_(matlitho); 1004 femmodel->parameters->FindParam(&istemporal,LoveIsTemporalEnum); 1005 femmodel->parameters->FindParam(&nstep,LoveIntStepsPerLayerEnum); 58 1006 59 1007 /*Initialize three love matrices: geoid, vertical and horizontal displacement (real and imaginary parts) */ 60 IssmDouble* LoveKr = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 61 IssmDouble* LoveHr = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 62 IssmDouble* LoveLr = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 63 IssmDouble* LoveKi = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 64 IssmDouble* LoveHi = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 65 IssmDouble* LoveLi = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 1008 IssmDouble* LoveKf = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 1009 IssmDouble* LoveHf = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 1010 IssmDouble* LoveLf = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)); 66 1011 67 1012 /*Initialize love kernels (real and imaginary parts): */ … … 69 1014 IssmDouble* LoveKernelsImag = xNewZeroInit<IssmDouble>(nfreq*(sh_nmax+1)*(matlitho->numlayers+1)*6); 70 1015 1016 love_init(femmodel,matlitho); 1017 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); 1018 femmodel->parameters->FindParam(&starting_layer,LoveStartingLayerEnum); 1019 IssmDouble* yi_prefactor=xNewZeroInit<IssmDouble>(6*6*nstep*matlitho->numlayers); 1020 IssmDouble* yi_righthandside=xNewZeroInit<IssmDouble>(nyi); 1021 IssmDouble* yi=xNewZeroInit<IssmDouble>(nyi*nyi); 1022 1023 //precalculate yi coefficients that do not depend on degree or frequency 1024 fill_yi_prefactor(yi_prefactor, NULL, NULL,femmodel, matlitho); 1025 for(int deg=sh_nmin;deg<sh_nmax+1;deg++){ 1026 1027 //precalculate yi coefficients that depend on degree but not frequency 1028 fill_yi_prefactor(yi_prefactor, °, NULL,femmodel, matlitho); 1029 1030 for (int fr=0;fr<nfreq;fr++){ 1031 omega=2.0*PI*frequencies[fr]; //angular frequency 1032 1033 //precalculate yi coefficients that depend on degree and frequency 1034 fill_yi_prefactor(yi_prefactor, °,&omega,femmodel, matlitho); 1035 1036 yi_boundary_conditions(yi_righthandside,deg,femmodel,matlitho); 1037 1038 build_yi_system(yi,deg,omega,yi_prefactor,femmodel,matlitho); 1039 1040 solve_yi_system(&loveh,&lovel,&lovek, deg, omega, yi, yi_righthandside,femmodel, matlitho); 1041 1042 LoveHf[deg*nfreq+fr]=loveh; 1043 LoveKf[deg*nfreq+fr]=lovek-1.0; 1044 LoveLf[deg*nfreq+fr]=lovel; 1045 1046 femmodel->parameters->FindParam(&nyi,LoveNYiEquationsEnum); //synchronize nyi in case we deleted a layer 1047 deleted_layer_offset=(matlitho->numlayers+1)*6-nyi;// =6 per deleted layer 1048 kernel_index=deg*nfreq*(matlitho->numlayers+1)*6 + 1049 fr*(matlitho->numlayers+1)*6 + 1050 deleted_layer_offset; 1051 for (int i=0;i<nyi;i++){ 1052 LoveKernelsReal[kernel_index+i]=yi_righthandside[i]; 1053 } 1054 } 1055 } 1056 1057 1058 xDelete<IssmDouble>(yi); 1059 xDelete<IssmDouble>(yi_righthandside); 1060 1061 1062 //Temporal love numbers 1063 if (istemporal){ 1064 int NTit; 1065 femmodel->parameters->FindParam(&NTit,LoveNTemporalIterationsEnum); 1066 int nt = nfreq/2/NTit; 1067 1068 IssmDouble* LoveHt=xNewZeroInit<IssmDouble>((sh_nmax+1)*nt); 1069 IssmDouble* LoveLt=xNewZeroInit<IssmDouble>((sh_nmax+1)*nt); 1070 IssmDouble* LoveKt=xNewZeroInit<IssmDouble>((sh_nmax+1)*nt); 1071 1072 love_freq_to_temporal(LoveHt,LoveLt,LoveKt,LoveHf,LoveLf,LoveKf,femmodel); 1073 1074 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKrEnum,LoveKt,sh_nmax+1,nt,0,0)); 1075 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHrEnum,LoveHt,sh_nmax+1,nt,0,0)); 1076 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLrEnum,LoveLt,sh_nmax+1,nt,0,0)); 1077 1078 xDelete<IssmDouble>(LoveHt); 1079 xDelete<IssmDouble>(LoveLt); 1080 xDelete<IssmDouble>(LoveKt); 1081 } 1082 1083 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKiEnum,LoveKf,sh_nmax+1,nfreq,0,0)); 1084 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHiEnum,LoveHf,sh_nmax+1,nfreq,0,0)); 1085 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLiEnum,LoveLf,sh_nmax+1,nfreq,0,0)); 1086 1087 71 1088 /*call the main module: */ 72 FourierLoveCorex(LoveKr,LoveKi,LoveHr,LoveHi,LoveLr,LoveLi,LoveKernelsReal,LoveKernelsImag, //output 73 nfreq,frequencies,sh_nmax,sh_nmin,g0,r0,mu0,allow_layer_deletion,forcing_type,verbosemod, //parameter inputs 74 matlitho->numlayers, matlitho->radius, matlitho->viscosity, matlitho->lame_lambda, matlitho->lame_mu, 75 matlitho->burgers_viscosity, matlitho->burgers_mu, matlitho->density, matlitho->isburgers, matlitho->issolid //matlitho inputs 76 ); 1089 //if (false){ 1090 //FourierLoveCorex(LoveKr,LoveKi,LoveHr,LoveHi,LoveLr,LoveLi,LoveKernelsReal,LoveKernelsImag, //output 1091 // nfreq,frequencies,sh_nmax,sh_nmin,g0,r0,mu0,allow_layer_deletion,forcing_type,verbosemod, //parameter inputs 1092 // matlitho->numlayers, matlitho->radius, matlitho->viscosity, matlitho->lame_lambda, matlitho->lame_mu, 1093 // matlitho->burgers_viscosity, matlitho->burgers_mu, matlitho->density, matlitho->rheologymodel, matlitho->issolid //matlitho inputs 1094 // ); 1095 //} 77 1096 78 1097 /*Add love matrices to results:*/ 79 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKrEnum,LoveKr,sh_nmax+1,nfreq,0,0)); 80 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHrEnum,LoveHr,sh_nmax+1,nfreq,0,0)); 81 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLrEnum,LoveLr,sh_nmax+1,nfreq,0,0)); 82 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKiEnum,LoveKi,sh_nmax+1,nfreq,0,0)); 83 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHiEnum,LoveHi,sh_nmax+1,nfreq,0,0)); 84 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLiEnum,LoveLi,sh_nmax+1,nfreq,0,0)); 85 /*Only when love_kernels is set unity*/ 1098 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKrEnum,LoveKr,sh_nmax+1,nfreq,0,0)); 1099 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHrEnum,LoveHr,sh_nmax+1,nfreq,0,0)); 1100 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLrEnum,LoveLr,sh_nmax+1,nfreq,0,0)); 1101 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKiEnum,LoveKi,sh_nmax+1,nfreq,0,0)); 1102 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveHiEnum,LoveHi,sh_nmax+1,nfreq,0,0)); 1103 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveLiEnum,LoveLi,sh_nmax+1,nfreq,0,0)); 1104 1105 /*Only when love_kernels is on*/ 86 1106 if (love_kernels==1) { 87 1107 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKernelsRealEnum,LoveKernelsReal,(sh_nmax+1)*(matlitho->numlayers+1)*6,nfreq,0,0)); 88 femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKernelsImagEnum,LoveKernelsImag,(sh_nmax+1)*(matlitho->numlayers+1)*6,nfreq,0,0));89 } 90 91 /*Free res sources:*/1108 //femmodel->results->AddObject(new GenericExternalResult<IssmDouble*>(femmodel->results->Size()+1,LoveKernelsImagEnum,LoveKernelsImag,(sh_nmax+1)*(matlitho->numlayers+1)*6,nfreq,0,0)); 1109 } 1110 1111 /*Free resources:*/ 92 1112 xDelete<IssmDouble>(frequencies); 93 xDelete<IssmDouble>(LoveK r);94 xDelete<IssmDouble>(LoveH r);95 xDelete<IssmDouble>(LoveL r);96 xDelete<IssmDouble>(LoveKi);97 xDelete<IssmDouble>(LoveHi);98 xDelete<IssmDouble>(LoveLi);1113 xDelete<IssmDouble>(LoveKf); 1114 xDelete<IssmDouble>(LoveHf); 1115 xDelete<IssmDouble>(LoveLf); 1116 //xDelete<IssmDouble>(LoveKi); 1117 //xDelete<IssmDouble>(LoveHi); 1118 //xDelete<IssmDouble>(LoveLi); 99 1119 xDelete<IssmDouble>(LoveKernelsReal); 100 1120 xDelete<IssmDouble>(LoveKernelsImag); 101 } 1121 } /*}}}*/ 1122
Note:
See TracChangeset
for help on using the changeset viewer.