source: issm/trunk-jpl/src/c/analyses/EnthalpyAnalysis.cpp@ 16888

Last change on this file since 16888 was 16888, checked in by Mathieu Morlighem, 11 years ago

CHG: added Enthalpy but not working

File size: 32.3 KB
Line 
1#include "./EnthalpyAnalysis.h"
2#include "../toolkits/toolkits.h"
3#include "../classes/classes.h"
4#include "../shared/shared.h"
5#include "../modules/modules.h"
6
7/*Model processing*/
8int EnthalpyAnalysis::DofsPerNode(int** doflist,int meshtype,int approximation){/*{{{*/
9 return 1;
10}/*}}}*/
11void EnthalpyAnalysis::UpdateParameters(Parameters* parameters,IoModel* iomodel,int solution_enum,int analysis_enum){/*{{{*/
12
13 int numoutputs;
14 char** requestedoutputs = NULL;
15
16 parameters->AddObject(iomodel->CopyConstantObject(ThermalStabilizationEnum));
17 parameters->AddObject(iomodel->CopyConstantObject(ThermalIsenthalpyEnum));
18 parameters->AddObject(iomodel->CopyConstantObject(ThermalIsdynamicbasalspcEnum));
19
20 iomodel->FetchData(&requestedoutputs,&numoutputs,ThermalRequestedOutputsEnum);
21 parameters->AddObject(new IntParam(ThermalNumRequestedOutputsEnum,numoutputs));
22 if(numoutputs)parameters->AddObject(new StringArrayParam(ThermalRequestedOutputsEnum,requestedoutputs,numoutputs));
23 iomodel->DeleteData(&requestedoutputs,numoutputs,ThermalRequestedOutputsEnum);
24}/*}}}*/
25void EnthalpyAnalysis::UpdateElements(Elements* elements,IoModel* iomodel,int analysis_counter,int analysis_type){/*{{{*/
26
27 bool dakota_analysis;
28 bool isenthalpy;
29
30 /*Now, is the model 3d? otherwise, do nothing: */
31 if(iomodel->meshtype==Mesh2DhorizontalEnum)return;
32
33 /*Is enthalpy requested?*/
34 iomodel->Constant(&isenthalpy,ThermalIsenthalpyEnum);
35 if(!isenthalpy) return;
36
37 /*Fetch data needed: */
38 iomodel->FetchData(3,TemperatureEnum,WaterfractionEnum,PressureEnum);
39
40 /*Update elements: */
41 int counter=0;
42 for(int i=0;i<iomodel->numberofelements;i++){
43 if(iomodel->my_elements[i]){
44 Element* element=(Element*)elements->GetObjectByOffset(counter);
45 element->Update(i,iomodel,analysis_counter,analysis_type,P1Enum);
46 counter++;
47 }
48 }
49
50 iomodel->Constant(&dakota_analysis,QmuIsdakotaEnum);
51
52 iomodel->FetchDataToInput(elements,ThicknessEnum);
53 iomodel->FetchDataToInput(elements,SurfaceEnum);
54 iomodel->FetchDataToInput(elements,BedEnum);
55 iomodel->FetchDataToInput(elements,FrictionCoefficientEnum);
56 iomodel->FetchDataToInput(elements,FrictionPEnum);
57 iomodel->FetchDataToInput(elements,FrictionQEnum);
58 iomodel->FetchDataToInput(elements,MaskIceLevelsetEnum);
59 iomodel->FetchDataToInput(elements,MaskGroundediceLevelsetEnum);
60 iomodel->FetchDataToInput(elements,MeshElementonbedEnum);
61 iomodel->FetchDataToInput(elements,MeshElementonsurfaceEnum);
62 iomodel->FetchDataToInput(elements,FlowequationElementEquationEnum);
63 iomodel->FetchDataToInput(elements,MaterialsRheologyBEnum);
64 iomodel->FetchDataToInput(elements,MaterialsRheologyNEnum);
65 iomodel->FetchDataToInput(elements,PressureEnum);
66 iomodel->FetchDataToInput(elements,TemperatureEnum);
67 iomodel->FetchDataToInput(elements,WaterfractionEnum);
68 iomodel->FetchDataToInput(elements,EnthalpyEnum);
69 iomodel->FetchDataToInput(elements,BasalforcingsGeothermalfluxEnum);
70 iomodel->FetchDataToInput(elements,WatercolumnEnum);
71 iomodel->FetchDataToInput(elements,BasalforcingsMeltingRateEnum);
72 iomodel->FetchDataToInput(elements,VxEnum);
73 iomodel->FetchDataToInput(elements,VyEnum);
74 iomodel->FetchDataToInput(elements,VzEnum);
75 InputUpdateFromConstantx(elements,0.,VxMeshEnum);
76 InputUpdateFromConstantx(elements,0.,VyMeshEnum);
77 InputUpdateFromConstantx(elements,0.,VzMeshEnum);
78 if(dakota_analysis){
79 elements->InputDuplicate(TemperatureEnum,QmuTemperatureEnum);
80 elements->InputDuplicate(BasalforcingsMeltingRateEnum,QmuMeltingEnum);
81 elements->InputDuplicate(VxMeshEnum,QmuVxMeshEnum);
82 elements->InputDuplicate(VxMeshEnum,QmuVyMeshEnum);
83 elements->InputDuplicate(VxMeshEnum,QmuVzMeshEnum);
84 }
85
86 /*Free data: */
87 iomodel->DeleteData(3,TemperatureEnum,WaterfractionEnum,PressureEnum);
88}/*}}}*/
89void EnthalpyAnalysis::CreateNodes(Nodes* nodes,IoModel* iomodel){/*{{{*/
90
91 if(iomodel->meshtype==Mesh3DEnum) iomodel->FetchData(2,MeshVertexonbedEnum,MeshVertexonsurfaceEnum);
92 ::CreateNodes(nodes,iomodel,EnthalpyAnalysisEnum,P1Enum);
93 iomodel->DeleteData(2,MeshVertexonbedEnum,MeshVertexonsurfaceEnum);
94}/*}}}*/
95void EnthalpyAnalysis::CreateConstraints(Constraints* constraints,IoModel* iomodel){/*{{{*/
96
97 /*Intermediary*/
98 int count;
99 int M,N;
100 bool spcpresent = false;
101 IssmDouble heatcapacity;
102 IssmDouble referencetemperature;
103
104 /*Output*/
105 IssmDouble *spcvector = NULL;
106 IssmDouble* times=NULL;
107 IssmDouble* values=NULL;
108
109 /*Fetch parameters: */
110 iomodel->Constant(&heatcapacity,MaterialsHeatcapacityEnum);
111 iomodel->Constant(&referencetemperature,ConstantsReferencetemperatureEnum);
112
113 /*return if 2d mesh*/
114 if(iomodel->meshtype==Mesh2DhorizontalEnum) return;
115
116 /*Fetch data: */
117 iomodel->FetchData(&spcvector,&M,&N,ThermalSpctemperatureEnum);
118
119 //FIX ME: SHOULD USE IOMODELCREATECONSTRAINTS
120 /*Transient or static?:*/
121 if(M==iomodel->numberofvertices){
122 /*static: just create Constraints objects*/
123 count=0;
124
125 for(int i=0;i<iomodel->numberofvertices;i++){
126 /*keep only this partition's nodes:*/
127 if((iomodel->my_vertices[i])){
128
129 if (!xIsNan<IssmDouble>(spcvector[i])){
130
131 constraints->AddObject(new SpcStatic(iomodel->constraintcounter+count+1,iomodel->nodecounter+i+1,1,heatcapacity*(spcvector[i]-referencetemperature),EnthalpyAnalysisEnum));
132 count++;
133
134 }
135 }
136 }
137 }
138 else if (M==(iomodel->numberofvertices+1)){
139 /*transient: create transient SpcTransient objects. Same logic, except we need to retrieve
140 * various times and values to initialize an SpcTransient object: */
141 count=0;
142
143 /*figure out times: */
144 times=xNew<IssmDouble>(N);
145 for(int j=0;j<N;j++){
146 times[j]=spcvector[(M-1)*N+j];
147 }
148
149 /*Create constraints from x,y,z: */
150 for(int i=0;i<iomodel->numberofvertices;i++){
151
152 /*keep only this partition's nodes:*/
153 if((iomodel->my_vertices[i])){
154
155 /*figure out times and values: */
156 values=xNew<IssmDouble>(N);
157 spcpresent=false;
158 for(int j=0;j<N;j++){
159 values[j]=heatcapacity*(spcvector[i*N+j]-referencetemperature);
160 if(!xIsNan<IssmDouble>(values[j]))spcpresent=true; //NaN means no spc by default
161 }
162
163 if(spcpresent){
164 constraints->AddObject(new SpcTransient(iomodel->constraintcounter+count+1,iomodel->nodecounter+i+1,1,N,times,values,EnthalpyAnalysisEnum));
165 count++;
166 }
167 xDelete<IssmDouble>(values);
168 }
169 }
170 }
171 else{
172 _error_("Size of field " << EnumToStringx(ThermalSpctemperatureEnum) << " not supported");
173 }
174
175 /*Free ressources:*/
176 iomodel->DeleteData(spcvector,ThermalSpctemperatureEnum);
177 xDelete<IssmDouble>(times);
178 xDelete<IssmDouble>(values);
179}/*}}}*/
180void EnthalpyAnalysis::CreateLoads(Loads* loads, IoModel* iomodel){/*{{{*/
181
182 /*No loads */
183}/*}}}*/
184
185/*Finite Element Analysis*/
186ElementMatrix* EnthalpyAnalysis::CreateKMatrix(Element* element){/*{{{*/
187
188 /*compute all stiffness matrices for this element*/
189 ElementMatrix* Ke1=CreateKMatrixVolume(element);
190 ElementMatrix* Ke2=CreateKMatrixShelf(element);
191 ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
192
193 /*clean-up and return*/
194 delete Ke1;
195 delete Ke2;
196 return Ke;
197}/*}}}*/
198ElementMatrix* EnthalpyAnalysis::CreateKMatrixVolume(Element* element){/*{{{*/
199
200 /*Intermediaries */
201 int stabilization;
202 IssmDouble Jdet,dt,u,v,w,um,vm,wm,vel;
203 IssmDouble h,hx,hy,hz,vx,vy,vz;
204 IssmDouble tau_parameter,diameter;
205 IssmDouble D_scalar;
206 IssmDouble* xyz_list = NULL;
207
208 /*Fetch number of nodes and dof for this finite element*/
209 int numnodes = element->GetNumberOfNodes();
210
211 /*Initialize Element vector and other vectors*/
212 ElementMatrix* Ke = element->NewElementMatrix();
213 IssmDouble* basis = xNew<IssmDouble>(numnodes);
214 IssmDouble* dbasis = xNew<IssmDouble>(3*numnodes);
215 IssmDouble* B = xNew<IssmDouble>(3*numnodes);
216 IssmDouble* Bprime = xNew<IssmDouble>(3*numnodes);
217 IssmDouble D[3][3] = {0.};
218 IssmDouble K[3][3];
219
220 /*Retrieve all inputs and parameters*/
221 element->GetVerticesCoordinates(&xyz_list);
222 element->FindParam(&dt,TimesteppingTimeStepEnum);
223 element->FindParam(&stabilization,ThermalStabilizationEnum);
224 IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoWaterEnum);
225 IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
226 IssmDouble gravity = element->GetMaterialParameter(ConstantsGEnum);
227 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
228 IssmDouble thermalconductivity = element->GetMaterialParameter(MaterialsThermalconductivityEnum);
229 Input* vx_input = element->GetInput(VxEnum); _assert_(vx_input);
230 Input* vy_input = element->GetInput(VyEnum); _assert_(vy_input);
231 Input* vz_input = element->GetInput(VzEnum); _assert_(vz_input);
232 Input* vxm_input = element->GetInput(VxMeshEnum); _assert_(vxm_input);
233 Input* vym_input = element->GetInput(VyMeshEnum); _assert_(vym_input);
234 Input* vzm_input = element->GetInput(VzMeshEnum); _assert_(vzm_input);
235 if(stabilization==2) diameter=element->MinEdgeLength(xyz_list);
236
237 /*Enthalpy diffusion parameter*/
238 IssmDouble kappa=this->EnthalpyDiffusionParameterVolume(element); _assert_(kappa>0.);
239
240 /* Start looping on the number of gaussian points: */
241 Gauss* gauss=element->NewGauss(2);
242 for(int ig=gauss->begin();ig<gauss->end();ig++){
243 gauss->GaussPoint(ig);
244
245 element->JacobianDeterminant(&Jdet,xyz_list,gauss);
246 D_scalar=gauss->weight*Jdet;
247 if(dt!=0.) D_scalar=D_scalar*dt;
248
249 /*Conduction: */
250 GetBConduct(B,element,xyz_list,gauss);
251 D[0][0]=D_scalar*kappa/rho_ice;
252 D[1][1]=D_scalar*kappa/rho_ice;
253 D[2][2]=D_scalar*kappa/rho_ice;
254 TripleMultiply(B,3,numnodes,1,
255 &D[0][0],3,3,0,
256 B,3,numnodes,0,
257 &Ke->values[0],1);
258
259 /*Advection: */
260 GetBAdvec(B,element,xyz_list,gauss);
261 GetBAdvecprime(Bprime,element,xyz_list,gauss);
262 vx_input->GetInputValue(&u,gauss); vxm_input->GetInputValue(&um,gauss); vx=u-um;
263 vy_input->GetInputValue(&v,gauss); vym_input->GetInputValue(&vm,gauss); vy=v-vm;
264 vz_input->GetInputValue(&w,gauss); vzm_input->GetInputValue(&wm,gauss); vz=w-wm;
265 D[0][0]=D_scalar*vx;
266 D[1][1]=D_scalar*vy;
267 D[2][2]=D_scalar*vz;
268 TripleMultiply(B,3,numnodes,1,
269 &D[0][0],3,3,0,
270 Bprime,3,numnodes,0,
271 &Ke->values[0],1);
272
273 /*Transient: */
274 if(dt!=0.){
275 D_scalar=gauss->weight*Jdet;
276 element->NodalFunctions(basis,gauss);
277 TripleMultiply(basis,numnodes,1,0,
278 &D_scalar,1,1,0,
279 basis,1,numnodes,0,
280 &Ke->values[0],1);
281 D_scalar=D_scalar*dt;
282 }
283
284 /*Artifficial diffusivity*/
285 if(stabilization==1){
286 element->ElementSizes(&hx,&hy,&hz);
287 vel=sqrt(vx*vx + vy*vy + vz*vz)+1.e-14;
288 h=sqrt( pow(hx*vx/vel,2) + pow(hy*vy/vel,2) + pow(hz*vz/vel,2));
289 K[0][0]=h/(2.*vel)*fabs(vx*vx); K[0][1]=h/(2.*vel)*fabs(vx*vy); K[0][2]=h/(2.*vel)*fabs(vx*vz);
290 K[1][0]=h/(2.*vel)*fabs(vy*vx); K[1][1]=h/(2.*vel)*fabs(vy*vy); K[1][2]=h/(2.*vel)*fabs(vy*vz);
291 K[2][0]=h/(2.*vel)*fabs(vz*vx); K[2][1]=h/(2.*vel)*fabs(vz*vy); K[2][2]=h/(2.*vel)*fabs(vz*vz);
292 for(int i=0;i<3;i++) for(int j=0;j<3;j++) K[i][j] = D_scalar*K[i][j];
293
294 GetBAdvecprime(Bprime,element,xyz_list,gauss);
295
296 TripleMultiply(Bprime,3,numnodes,1,
297 &K[0][0],3,3,0,
298 Bprime,3,numnodes,0,
299 &Ke->values[0],1);
300 }
301 else if(stabilization==2){
302 element->NodalFunctionsDerivatives(dbasis,xyz_list,gauss);
303 tau_parameter=element->StabilizationParameter(u-um,v-vm,w-wm,diameter,kappa/rho_ice);
304 for(int i=0;i<numnodes;i++){
305 for(int j=0;j<numnodes;j++){
306 Ke->values[i*numnodes+j]+=tau_parameter*D_scalar*
307 ((u-um)*dbasis[0*3+i]+(v-vm)*dbasis[1*3+i]+(w-wm)*dbasis[2*3+i])*((u-um)*dbasis[0*3+j]+(v-vm)*dbasis[1*3+j]+(w-wm)*dbasis[2*3+j]);
308 }
309 }
310 if(dt!=0.){
311 for(int i=0;i<numnodes;i++){
312 for(int j=0;j<numnodes;j++){
313 Ke->values[i*numnodes+j]+=tau_parameter*D_scalar*basis[j]*((u-um)*dbasis[0*3+i]+(v-vm)*dbasis[1*3+i]+(w-wm)*dbasis[2*3+i]);
314 }
315 }
316 }
317 }
318 }
319
320 /*Clean up and return*/
321 xDelete<IssmDouble>(xyz_list);
322 xDelete<IssmDouble>(basis);
323 xDelete<IssmDouble>(dbasis);
324 xDelete<IssmDouble>(B);
325 xDelete<IssmDouble>(Bprime);
326 delete gauss;
327 return Ke;
328}/*}}}*/
329ElementMatrix* EnthalpyAnalysis::CreateKMatrixShelf(Element* element){/*{{{*/
330
331 /*Initialize Element matrix and return if necessary*/
332 if(!element->IsOnBed() || !element->IsFloating()) return NULL;
333
334 IssmDouble dt,Jdet,D;
335 IssmDouble *xyz_list_base = NULL;
336
337 /*Get basal element*/
338 if(!element->IsOnBed() || !element->IsFloating()) return NULL;
339
340 /*Fetch number of nodes for this finite element*/
341 int numnodes = element->GetNumberOfNodes();
342
343 /*Initialize vectors*/
344 ElementMatrix* Ke = element->NewElementMatrix();
345 IssmDouble* basis = xNew<IssmDouble>(numnodes);
346
347 /*Retrieve all inputs and parameters*/
348 element->GetVerticesCoordinatesBase(&xyz_list_base);
349 element->FindParam(&dt,TimesteppingTimeStepEnum);
350 IssmDouble gravity = element->GetMaterialParameter(ConstantsGEnum);
351 IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoWaterEnum);
352 IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
353 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
354 IssmDouble mixed_layer_capacity= element->GetMaterialParameter(MaterialsMixedLayerCapacityEnum);
355 IssmDouble thermal_exchange_vel= element->GetMaterialParameter(MaterialsThermalExchangeVelocityEnum);
356
357 /* Start looping on the number of gaussian points: */
358 Gauss* gauss=element->NewGaussBase(2);
359 for(int ig=gauss->begin();ig<gauss->end();ig++){
360 gauss->GaussPoint(ig);
361
362 element->JacobianDeterminantBase(&Jdet,xyz_list_base,gauss);
363 element->NodalFunctions(basis,gauss);
364
365 D=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_vel/(heatcapacity*rho_ice);
366 if(reCast<bool,IssmDouble>(dt)) D=dt*D;
367 TripleMultiply(basis,numnodes,1,0,
368 &D,1,1,0,
369 basis,1,numnodes,0,
370 &Ke->values[0],1);
371
372 }
373
374 /*Clean up and return*/
375 delete gauss;
376 xDelete<IssmDouble>(basis);
377 xDelete<IssmDouble>(xyz_list_base);
378 return Ke;
379}/*}}}*/
380ElementVector* EnthalpyAnalysis::CreatePVector(Element* element){/*{{{*/
381
382 /*compute all load vectors for this element*/
383 ElementVector* pe1=CreatePVectorVolume(element);
384 ElementVector* pe2=CreatePVectorSheet(element);
385 ElementVector* pe3=CreatePVectorShelf(element);
386 ElementVector* pe =new ElementVector(pe1,pe2,pe3);
387
388 /*clean-up and return*/
389 delete pe1;
390 delete pe2;
391 delete pe3;
392 return pe;
393}/*}}}*/
394ElementVector* EnthalpyAnalysis::CreatePVectorVolume(Element* element){/*{{{*/
395
396 /*Intermediaries*/
397 int stabilization;
398 IssmDouble Jdet,phi,dt;
399 IssmDouble enthalpy;
400 IssmDouble kappa,tau_parameter,diameter;
401 IssmDouble u,v,w;
402 IssmDouble scalar_def,scalar_transient;
403 IssmDouble* xyz_list = NULL;
404
405 /*Fetch number of nodes and dof for this finite element*/
406 int numnodes = element->GetNumberOfNodes();
407 int numvertices = element->GetNumberOfVertices();
408
409 /*Initialize Element vector*/
410 ElementVector* pe = element->NewElementVector();
411 IssmDouble* basis = xNew<IssmDouble>(numnodes);
412 IssmDouble* dbasis = xNew<IssmDouble>(3*numnodes);
413 IssmDouble* pressure = xNew<IssmDouble>(numvertices);
414 IssmDouble* enthalpypicard = xNew<IssmDouble>(numvertices);
415
416 /*Retrieve all inputs and parameters*/
417 element->GetVerticesCoordinates(&xyz_list);
418 IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
419 IssmDouble thermalconductivity = element->GetMaterialParameter(MaterialsThermalconductivityEnum);
420 element->FindParam(&dt,TimesteppingTimeStepEnum);
421 element->FindParam(&stabilization,ThermalStabilizationEnum);
422 Input* vx_input=element->GetInput(VxEnum); _assert_(vx_input);
423 Input* vy_input=element->GetInput(VyEnum); _assert_(vy_input);
424 Input* vz_input=element->GetInput(VzEnum); _assert_(vz_input);
425 Input* enthalpy_input = NULL;
426 if(reCast<bool,IssmDouble>(dt)){enthalpy_input = element->GetInput(EnthalpyEnum); _assert_(enthalpy_input);}
427 if(stabilization==2){
428 element->GetInputListOnVertices(enthalpypicard,EnthalpyPicardEnum);
429 element->GetInputListOnVertices(pressure,PressureEnum);
430 diameter=element->MinEdgeLength(xyz_list);
431 }
432
433 /* Start looping on the number of gaussian points: */
434 Gauss* gauss=element->NewGauss(3);
435 for(int ig=gauss->begin();ig<gauss->end();ig++){
436 gauss->GaussPoint(ig);
437
438 element->JacobianDeterminant(&Jdet,xyz_list,gauss);
439 element->NodalFunctions(basis,gauss);
440 element->ViscousHeating(&phi,xyz_list,gauss,vx_input,vy_input,vz_input);
441
442 scalar_def=phi/rho_ice*Jdet*gauss->weight;
443 if(reCast<bool,IssmDouble>(dt)) scalar_def=scalar_def*dt;
444
445 /*TODO: add -beta*laplace T_m(p)*/
446 for(int i=0;i<numnodes;i++) pe->values[i]+=scalar_def*basis[i];
447
448 /* Build transient now */
449 if(reCast<bool,IssmDouble>(dt)){
450 enthalpy_input->GetInputValue(&enthalpy, gauss);
451 scalar_transient=enthalpy*Jdet*gauss->weight;
452 for(int i=0;i<numnodes;i++) pe->values[i]+=scalar_transient*basis[i];
453 }
454
455 if(stabilization==2){
456 element->NodalFunctionsDerivatives(dbasis,xyz_list,gauss);
457
458 vx_input->GetInputValue(&u,gauss);
459 vy_input->GetInputValue(&v,gauss);
460 vz_input->GetInputValue(&w,gauss);
461 kappa = element->EnthalpyDiffusionParameterVolume(numvertices,enthalpypicard,pressure) / rho_ice;
462 tau_parameter = element->StabilizationParameter(u,v,w,diameter,kappa);
463
464 for(int i=0;i<numnodes;i++) pe->values[i]+=tau_parameter*scalar_def*(u*dbasis[0*3+i]+v*dbasis[1*3+i]+w*dbasis[2*3+i]);
465 if(reCast<bool,IssmDouble>(dt)){
466 for(int i=0;i<numnodes;i++) pe->values[i]+=tau_parameter*scalar_transient*(u*dbasis[0*3+i]+v*dbasis[1*3+i]+w*dbasis[2*3+i]);
467 }
468 }
469 }
470
471 /*Clean up and return*/
472 xDelete<IssmDouble>(basis);
473 xDelete<IssmDouble>(dbasis);
474 xDelete<IssmDouble>(pressure);
475 xDelete<IssmDouble>(enthalpypicard);
476 xDelete<IssmDouble>(xyz_list);
477 delete gauss;
478 return pe;
479
480}/*}}}*/
481ElementVector* EnthalpyAnalysis::CreatePVectorSheet(Element* element){/*{{{*/
482
483 /* Geothermal flux on ice sheet base and basal friction */
484 if(!element->IsOnBed() || element->IsFloating()) return NULL;
485
486 IssmDouble dt,Jdet,enthalpy,pressure,watercolumn,geothermalflux,vx,vy,vz;
487 IssmDouble enthalpyup,pressureup,alpha2,scalar,basalfriction,heatflux;
488 IssmDouble *xyz_list_base = NULL;
489
490 /*Fetch number of nodes for this finite element*/
491 int numnodes = element->GetNumberOfNodes();
492
493 /*Initialize vectors*/
494 ElementVector* pe = element->NewElementVector();
495 IssmDouble* basis = xNew<IssmDouble>(numnodes);
496
497 /*Retrieve all inputs and parameters*/
498 element->GetVerticesCoordinatesBase(&xyz_list_base);
499 element->FindParam(&dt,TimesteppingTimeStepEnum);
500 Input* vx_input = element->GetInput(VxEnum); _assert_(vx_input);
501 Input* vy_input = element->GetInput(VyEnum); _assert_(vy_input);
502 Input* vz_input = element->GetInput(VzEnum); _assert_(vz_input);
503 Input* enthalpy_input = element->GetInput(EnthalpyPicardEnum); _assert_(enthalpy_input);
504 Input* pressure_input = element->GetInput(PressureEnum); _assert_(pressure_input);
505 Input* geothermalflux_input = element->GetInput(BasalforcingsGeothermalfluxEnum); _assert_(geothermalflux_input);
506 Input* watercolumn_input = element->GetInput(WatercolumnEnum); _assert_(watercolumn_input);
507 IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
508 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
509
510 /*Build friction element, needed later: */
511 Friction* friction=new Friction(element,3);
512
513 /* Start looping on the number of gaussian points: */
514 Gauss* gauss = element->NewGaussBase(2);
515 Gauss* gaussup = element->NewGaussTop(2);
516 for(int ig=gauss->begin();ig<gauss->end();ig++){
517 gauss->GaussPoint(ig);
518
519 element->JacobianDeterminantBase(&Jdet,xyz_list_base,gauss);
520 element->NodalFunctions(basis,gauss);
521
522 enthalpy_input->GetInputValue(&enthalpy,gauss);
523 pressure_input->GetInputValue(&pressure,gauss);
524 watercolumn_input->GetInputValue(&watercolumn,gauss);
525
526 if((watercolumn<=0.) && (enthalpy < PureIceEnthalpy(element,pressure))){
527 /* the above check is equivalent to
528 NOT ((watercolumn>0.) AND (enthalpy<PIE)) AND (enthalpy<PIE)*/
529 geothermalflux_input->GetInputValue(&geothermalflux,gauss);
530
531 friction->GetAlpha2(&alpha2,gauss,vx_input,vy_input,vz_input);
532 vx_input->GetInputValue(&vx,gauss);
533 vy_input->GetInputValue(&vy,gauss);
534 vz_input->GetInputValue(&vz,gauss);
535 basalfriction = alpha2*(vx*vx + vy*vy + vz*vz);
536 heatflux = (basalfriction+geothermalflux)/(rho_ice);
537
538 scalar = gauss->weight*Jdet*heatflux;
539 if(dt!=0.) scalar=dt*scalar;
540
541 for(int i=0;i<numnodes;i++) pe->values[i]+=scalar*basis[i];
542 }
543 else if(enthalpy >= PureIceEnthalpy(element,pressure)){
544 /* check positive thickness of temperate basal ice layer */
545 enthalpy_input->GetInputValue(&enthalpyup,gaussup);
546 pressure_input->GetInputValue(&pressureup,gaussup);
547 if(enthalpyup >= PureIceEnthalpy(element,pressureup)){
548 // TODO: temperate ice has positive thickness: grad enthalpy*n=0.
549 }
550 else{
551 // only base temperate, set Dirichlet BCs in Penta::UpdateBasalConstraintsEnthalpy()
552 }
553 }
554 else{
555 // base cold, but watercolumn positive. Set base to h_pmp.
556 }
557 }
558
559 /*Clean up and return*/
560 delete gauss;
561 delete gaussup;
562 delete friction;
563 xDelete<IssmDouble>(basis);
564 xDelete<IssmDouble>(xyz_list_base);
565 return pe;
566
567}/*}}}*/
568ElementVector* EnthalpyAnalysis::CreatePVectorShelf(Element* element){/*{{{*/
569
570 /*Get basal element*/
571 if(!element->IsOnBed() || !element->IsFloating()) return NULL;
572
573 IssmDouble h_pmp,dt,Jdet,scalar_ocean,pressure;
574 IssmDouble *xyz_list_base = NULL;
575
576 /*Fetch number of nodes for this finite element*/
577 int numnodes = element->GetNumberOfNodes();
578
579 /*Initialize vectors*/
580 ElementVector* pe = element->NewElementVector();
581 IssmDouble* basis = xNew<IssmDouble>(numnodes);
582
583 /*Retrieve all inputs and parameters*/
584 element->GetVerticesCoordinatesBase(&xyz_list_base);
585 element->FindParam(&dt,TimesteppingTimeStepEnum);
586 Input* pressure_input=element->GetInput(PressureEnum); _assert_(pressure_input);
587 IssmDouble gravity = element->GetMaterialParameter(ConstantsGEnum);
588 IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoWaterEnum);
589 IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
590 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
591 IssmDouble mixed_layer_capacity= element->GetMaterialParameter(MaterialsMixedLayerCapacityEnum);
592 IssmDouble thermal_exchange_vel= element->GetMaterialParameter(MaterialsThermalExchangeVelocityEnum);
593
594 /* Start looping on the number of gaussian points: */
595 Gauss* gauss=element->NewGaussBase(2);
596 for(int ig=gauss->begin();ig<gauss->end();ig++){
597 gauss->GaussPoint(ig);
598
599 element->JacobianDeterminantBase(&Jdet,xyz_list_base,gauss);
600 element->NodalFunctions(basis,gauss);
601
602 pressure_input->GetInputValue(&pressure,gauss);
603 h_pmp=element->PureIceEnthalpy(pressure);
604
605 scalar_ocean=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_vel*h_pmp/(heatcapacity*rho_ice);
606 if(reCast<bool,IssmDouble>(dt)) scalar_ocean=dt*scalar_ocean;
607
608 for(int i=0;i<numnodes;i++) pe->values[i]+=scalar_ocean*basis[i];
609 }
610
611 /*Clean up and return*/
612 delete gauss;
613 xDelete<IssmDouble>(basis);
614 xDelete<IssmDouble>(xyz_list_base);
615 return pe;
616}/*}}}*/
617void EnthalpyAnalysis::GetBConduct(IssmDouble* B,Element* element,IssmDouble* xyz_list,Gauss* gauss){/*{{{*/
618 /*Compute B matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1.
619 * For node i, Bi' can be expressed in the actual coordinate system
620 * by:
621 * Bi_conduct=[ dh/dx ]
622 * [ dh/dy ]
623 * [ dh/dz ]
624 * where h is the interpolation function for node i.
625 *
626 * We assume B has been allocated already, of size: 3x(NDOF1*numnodes)
627 */
628
629 /*Fetch number of nodes for this finite element*/
630 int numnodes = element->GetNumberOfNodes();
631
632 /*Get nodal functions derivatives*/
633 IssmDouble* dbasis=xNew<IssmDouble>(3*numnodes);
634 element->NodalFunctionsDerivatives(dbasis,xyz_list,gauss);
635
636 /*Build B: */
637 for(int i=0;i<numnodes;i++){
638 B[numnodes*0+i] = dbasis[0*numnodes+i];
639 B[numnodes*1+i] = dbasis[1*numnodes+i];
640 B[numnodes*2+i] = dbasis[2*numnodes+i];
641 }
642
643 /*Clean-up*/
644 xDelete<IssmDouble>(dbasis);
645}/*}}}*/
646void EnthalpyAnalysis::GetBAdvec(IssmDouble* B,Element* element,IssmDouble* xyz_list,Gauss* gauss){/*{{{*/
647 /*Compute B matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1.
648 * For node i, Bi' can be expressed in the actual coordinate system
649 * by:
650 * Bi_advec =[ h ]
651 * [ h ]
652 * [ h ]
653 * where h is the interpolation function for node i.
654 *
655 * We assume B has been allocated already, of size: 3x(NDOF1*NUMNODESP1)
656 */
657
658 /*Fetch number of nodes for this finite element*/
659 int numnodes = element->GetNumberOfNodes();
660
661 /*Get nodal functions*/
662 IssmDouble* basis=xNew<IssmDouble>(numnodes);
663 element->NodalFunctions(basis,gauss);
664
665 /*Build B: */
666 for(int i=0;i<numnodes;i++){
667 B[numnodes*0+i] = basis[i];
668 B[numnodes*1+i] = basis[i];
669 B[numnodes*2+i] = basis[i];
670 }
671
672 /*Clean-up*/
673 xDelete<IssmDouble>(basis);
674}/*}}}*/
675void EnthalpyAnalysis::GetBAdvecprime(IssmDouble* B,Element* element,IssmDouble* xyz_list,Gauss* gauss){/*{{{*/
676 /*Compute B matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1.
677 * For node i, Bi' can be expressed in the actual coordinate system
678 * by:
679 * Biprime_advec=[ dh/dx ]
680 * [ dh/dy ]
681 * [ dh/dz ]
682 * where h is the interpolation function for node i.
683 *
684 * We assume B has been allocated already, of size: 3x(NDOF1*numnodes)
685 */
686
687 /*Fetch number of nodes for this finite element*/
688 int numnodes = element->GetNumberOfNodes();
689
690 /*Get nodal functions derivatives*/
691 IssmDouble* dbasis=xNew<IssmDouble>(3*numnodes);
692 element->NodalFunctionsDerivatives(dbasis,xyz_list,gauss);
693
694 /*Build B: */
695 for(int i=0;i<numnodes;i++){
696 B[numnodes*0+i] = dbasis[0*numnodes+i];
697 B[numnodes*1+i] = dbasis[1*numnodes+i];
698 B[numnodes*2+i] = dbasis[2*numnodes+i];
699 }
700
701 /*Clean-up*/
702 xDelete<IssmDouble>(dbasis);
703}/*}}}*/
704void EnthalpyAnalysis::GetSolutionFromInputs(Vector<IssmDouble>* solution,Element* element){/*{{{*/
705 element->GetSolutionFromInputsOneDof(solution,EnthalpyEnum);
706}/*}}}*/
707void EnthalpyAnalysis::InputUpdateFromSolution(IssmDouble* solution,Element* element){/*{{{*/
708
709 bool converged;
710 int i,rheology_law;
711 IssmDouble B_average,s_average,T_average=0.,P_average=0.;
712 int *doflist = NULL;
713 IssmDouble *xyz_list = NULL;
714
715 /*Fetch number of nodes and dof for this finite element*/
716 int numnodes = element->GetNumberOfNodes();
717
718 /*Fetch dof list and allocate solution vector*/
719 element->GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
720 IssmDouble* values = xNew<IssmDouble>(numnodes);
721 IssmDouble* pressure = xNew<IssmDouble>(numnodes);
722 IssmDouble* surface = xNew<IssmDouble>(numnodes);
723 IssmDouble* B = xNew<IssmDouble>(numnodes);
724 IssmDouble* temperature = xNew<IssmDouble>(numnodes);
725 IssmDouble* waterfraction = xNew<IssmDouble>(numnodes);
726
727 /*Use the dof list to index into the solution vector: */
728 for(i=0;i<numnodes;i++){
729 values[i]=solution[doflist[i]];
730
731 /*Check solution*/
732 if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
733 }
734
735 /*Get all inputs and parameters*/
736 element->GetInputValue(&converged,ConvergedEnum);
737 element->GetInputListOnNodes(&pressure[0],PressureEnum);
738 if(converged){
739 for(i=0;i<numnodes;i++){
740 element->EnthalpyToThermal(&temperature[i],&waterfraction[i],values[i],pressure[i]);
741 if(waterfraction[i]<0.) _error_("Negative water fraction found in solution vector");
742 if(waterfraction[i]>1.) _error_("Water fraction >1 found in solution vector");
743 }
744 element->AddInput(EnthalpyEnum,values,P1Enum);
745 element->AddInput(WaterfractionEnum,waterfraction,P1Enum);
746 element->AddInput(TemperatureEnum,temperature,P1Enum);
747
748 /*Update Rheology only if converged (we must make sure that the temperature is below melting point
749 * otherwise the rheology could be negative*/
750 element->FindParam(&rheology_law,MaterialsRheologyLawEnum);
751 element->GetInputListOnNodes(&surface[0],SurfaceEnum);
752 switch(rheology_law){
753 case NoneEnum:
754 /*Do nothing: B is not temperature dependent*/
755 break;
756 case PatersonEnum:
757 for(i=0;i<numnodes;i++) B[i]=Paterson(temperature[i]);
758 element->AddMaterialInput(MaterialsRheologyBEnum,&B[0],P1Enum);
759 break;
760 case ArrheniusEnum:
761 element->GetVerticesCoordinates(&xyz_list);
762 for(i=0;i<numnodes;i++) B[i]=Arrhenius(temperature[i],surface[i]-xyz_list[i*3+2],element->GetMaterialParameter(MaterialsRheologyNEnum));
763 element->AddMaterialInput(MaterialsRheologyBEnum,&B[0],P1Enum);
764 break;
765 case LliboutryDuvalEnum:
766 for(i=0;i<numnodes;i++) B[i]=LliboutryDuval(values[i],pressure[i],element->GetMaterialParameter(MaterialsRheologyNEnum),element->GetMaterialParameter(MaterialsBetaEnum),element->GetMaterialParameter(ConstantsReferencetemperatureEnum),element->GetMaterialParameter(MaterialsHeatcapacityEnum),element->GetMaterialParameter(MaterialsLatentheatEnum));
767 element->AddMaterialInput(MaterialsRheologyBEnum,&B[0],P1Enum);
768 break;
769 default: _error_("Rheology law " << EnumToStringx(rheology_law) << " not supported yet");
770 }
771 }
772 else{
773 element->AddInput(EnthalpyPicardEnum,values,P1Enum);
774 }
775
776 /*Free ressources:*/
777 xDelete<IssmDouble>(values);
778 xDelete<IssmDouble>(pressure);
779 xDelete<IssmDouble>(surface);
780 xDelete<IssmDouble>(B);
781 xDelete<IssmDouble>(temperature);
782 xDelete<IssmDouble>(waterfraction);
783 xDelete<IssmDouble>(xyz_list);
784 xDelete<int>(doflist);
785}/*}}}*/
786
787/*Intermediaries*/
788IssmDouble EnthalpyAnalysis::EnthalpyDiffusionParameter(Element* element,IssmDouble enthalpy,IssmDouble pressure){/*{{{*/
789
790 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
791 IssmDouble temperateiceconductivity = element->GetMaterialParameter(MaterialsTemperateiceconductivityEnum);
792 IssmDouble thermalconductivity = element->GetMaterialParameter(MaterialsThermalconductivityEnum);
793
794 if(enthalpy < PureIceEnthalpy(element,pressure)){
795 return thermalconductivity/heatcapacity;
796 }
797 else{
798 return temperateiceconductivity/heatcapacity;
799 }
800}/*}}}*/
801IssmDouble EnthalpyAnalysis::EnthalpyDiffusionParameterVolume(Element* element){/*{{{*/
802
803 int iv;
804 IssmDouble lambda; /* fraction of cold ice */
805 IssmDouble kappa ,kappa_c,kappa_t; /* enthalpy conductivities */
806 IssmDouble Hc,Ht;
807
808
809 /*Get pressures and enthalpies on vertices*/
810 int numvertices = element->GetNumberOfVertices();
811 IssmDouble* pressures = xNew<IssmDouble>(numvertices);
812 IssmDouble* enthalpies = xNew<IssmDouble>(numvertices);
813 IssmDouble* PIE = xNew<IssmDouble>(numvertices);
814 IssmDouble* dHpmp = xNew<IssmDouble>(numvertices);
815 element->GetInputListOnVertices(pressures,PressureEnum);
816 element->GetInputListOnVertices(enthalpies,EnthalpyEnum);
817 for(iv=0;iv<numvertices;iv++){
818 PIE[iv] = PureIceEnthalpy(element,pressures[iv]);
819 dHpmp[iv] = enthalpies[iv]-PIE[iv];
820 }
821
822 bool allequalsign = true;
823 if(dHpmp[0]<0.){
824 for(iv=1; iv<numvertices;iv++) allequalsign=(allequalsign && (dHpmp[iv]<0.));
825 }
826 else{
827 for(iv=1; iv<numvertices;iv++) allequalsign=(allequalsign && (dHpmp[iv]>=0.));
828 }
829
830 if(allequalsign){
831 kappa = EnthalpyDiffusionParameter(element,enthalpies[0],pressures[0]);
832 }
833 else{
834 /* return harmonic mean of thermal conductivities, weighted by fraction of cold/temperate ice,
835 cf Patankar 1980, pp44 */
836 kappa_c = EnthalpyDiffusionParameter(element,PureIceEnthalpy(element,0.)-1.,0.);
837 kappa_t = EnthalpyDiffusionParameter(element,PureIceEnthalpy(element,0.)+1.,0.);
838 Hc=0.; Ht=0.;
839 for(iv=0; iv<numvertices;iv++){
840 if(enthalpies[iv]<PIE[iv])
841 Hc+=(PIE[iv]-enthalpies[iv]);
842 else
843 Ht+=(enthalpies[iv]-PIE[iv]);
844 }
845 _assert_((Hc+Ht)>0.);
846 lambda = Hc/(Hc+Ht);
847 kappa = 1./(lambda/kappa_c + (1.-lambda)/kappa_t);
848 }
849
850 /*Clean up and return*/
851 xDelete<IssmDouble>(PIE);
852 xDelete<IssmDouble>(dHpmp);
853 xDelete<IssmDouble>(pressures);
854 xDelete<IssmDouble>(enthalpies);
855 return kappa;
856}
857/*}}}*/
858IssmDouble EnthalpyAnalysis::PureIceEnthalpy(Element* element,IssmDouble pressure){/*{{{*/
859
860 IssmDouble heatcapacity = element->GetMaterialParameter(MaterialsHeatcapacityEnum);
861 IssmDouble referencetemperature = element->GetMaterialParameter(ConstantsReferencetemperatureEnum);
862
863 return heatcapacity*(TMeltingPoint(element,pressure)-referencetemperature);
864}/*}}}*/
865IssmDouble EnthalpyAnalysis::TMeltingPoint(Element* element,IssmDouble pressure){/*{{{*/
866
867 IssmDouble meltingpoint = element->GetMaterialParameter(MaterialsMeltingpointEnum);
868 IssmDouble beta = element->GetMaterialParameter(MaterialsBetaEnum);
869
870 return meltingpoint-beta*pressure;
871}/*}}}*/
Note: See TracBrowser for help on using the repository browser.