| 1 | #include "./HydrologySommersAnalysis.h"
|
|---|
| 2 | #include "../toolkits/toolkits.h"
|
|---|
| 3 | #include "../classes/classes.h"
|
|---|
| 4 | #include "../shared/shared.h"
|
|---|
| 5 | #include "../modules/modules.h"
|
|---|
| 6 |
|
|---|
| 7 | /*Define 2 hardcoded parameters*/
|
|---|
| 8 | #define OMEGA 0.001 // parameter controlling transition to nonlinear resistance in basal system (dimensionless)
|
|---|
| 9 | #define NU 1.787e-6 //kinematic water viscosity m^2/s
|
|---|
| 10 | #define CT 7.5e-8 // Clapeyron slope (K/Pa)
|
|---|
| 11 | #define CW 4.22e3 // specific heat capacity of water (J/kg/K)
|
|---|
| 12 |
|
|---|
| 13 | /*Model processing*/
|
|---|
| 14 | void HydrologySommersAnalysis::CreateConstraints(Constraints* constraints,IoModel* iomodel){/*{{{*/
|
|---|
| 15 |
|
|---|
| 16 | /*retrieve some parameters: */
|
|---|
| 17 | int hydrology_model;
|
|---|
| 18 | iomodel->FindConstant(&hydrology_model,"md.hydrology.model");
|
|---|
| 19 |
|
|---|
| 20 | if(hydrology_model!=HydrologysommersEnum) return;
|
|---|
| 21 |
|
|---|
| 22 | IoModelToConstraintsx(constraints,iomodel,"md.hydrology.spchead",HydrologySommersAnalysisEnum,P1Enum);
|
|---|
| 23 |
|
|---|
| 24 | }/*}}}*/
|
|---|
| 25 | void HydrologySommersAnalysis::CreateLoads(Loads* loads, IoModel* iomodel){/*{{{*/
|
|---|
| 26 |
|
|---|
| 27 | /*Fetch parameters: */
|
|---|
| 28 | int hydrology_model;
|
|---|
| 29 | iomodel->FindConstant(&hydrology_model,"md.hydrology.model");
|
|---|
| 30 |
|
|---|
| 31 | /*Now, do we really want Sommers?*/
|
|---|
| 32 | if(hydrology_model!=HydrologysommersEnum) return;
|
|---|
| 33 |
|
|---|
| 34 | /*Create discrete loads for Moulins*/
|
|---|
| 35 | CreateSingleNodeToElementConnectivity(iomodel);
|
|---|
| 36 | for(int i=0;i<iomodel->numberofvertices;i++){
|
|---|
| 37 | if (iomodel->domaintype!=Domain3DEnum){
|
|---|
| 38 | /*keep only this partition's nodes:*/
|
|---|
| 39 | if(iomodel->my_vertices[i]){
|
|---|
| 40 | loads->AddObject(new Moulin(iomodel->loadcounter+i+1,i,iomodel,HydrologySommersAnalysisEnum));
|
|---|
| 41 | }
|
|---|
| 42 | }
|
|---|
| 43 | else if(reCast<int>(iomodel->Data("md.mesh.vertexonbase")[i])){
|
|---|
| 44 | if(iomodel->my_vertices[i]){
|
|---|
| 45 | loads->AddObject(new Moulin(iomodel->loadcounter+i+1,i,iomodel,HydrologySommersAnalysisEnum));
|
|---|
| 46 | }
|
|---|
| 47 | }
|
|---|
| 48 | }
|
|---|
| 49 | iomodel->DeleteData(1,"md.mesh.vertexonbase");
|
|---|
| 50 |
|
|---|
| 51 | /*Deal with Neumann BC*/
|
|---|
| 52 | int M,N;
|
|---|
| 53 | int *segments = NULL;
|
|---|
| 54 | iomodel->FetchData(&segments,&M,&N,"md.mesh.segments");
|
|---|
| 55 |
|
|---|
| 56 | /*Check that the size seem right*/
|
|---|
| 57 | _assert_(N==3); _assert_(M>=3);
|
|---|
| 58 | for(int i=0;i<M;i++){
|
|---|
| 59 | if(iomodel->my_elements[segments[i*3+2]-1]){
|
|---|
| 60 | loads->AddObject(new Neumannflux(iomodel->loadcounter+i+1,i,iomodel,segments,HydrologySommersAnalysisEnum));
|
|---|
| 61 | }
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | xDelete<int>(segments);
|
|---|
| 65 |
|
|---|
| 66 | }/*}}}*/
|
|---|
| 67 | void HydrologySommersAnalysis::CreateNodes(Nodes* nodes,IoModel* iomodel){/*{{{*/
|
|---|
| 68 |
|
|---|
| 69 | /*Fetch parameters: */
|
|---|
| 70 | int hydrology_model;
|
|---|
| 71 | iomodel->FindConstant(&hydrology_model,"md.hydrology.model");
|
|---|
| 72 |
|
|---|
| 73 | /*Now, do we really want Sommers?*/
|
|---|
| 74 | if(hydrology_model!=HydrologysommersEnum) return;
|
|---|
| 75 |
|
|---|
| 76 | if(iomodel->domaintype==Domain3DEnum) iomodel->FetchData(2,"md.mesh.vertexonbase","md.mesh.vertexonsurface");
|
|---|
| 77 | ::CreateNodes(nodes,iomodel,HydrologySommersAnalysisEnum,P1Enum);
|
|---|
| 78 | iomodel->DeleteData(2,"md.mesh.vertexonbase","md.mesh.vertexonsurface");
|
|---|
| 79 | }/*}}}*/
|
|---|
| 80 | int HydrologySommersAnalysis::DofsPerNode(int** doflist,int domaintype,int approximation){/*{{{*/
|
|---|
| 81 | return 1;
|
|---|
| 82 | }/*}}}*/
|
|---|
| 83 | void HydrologySommersAnalysis::UpdateElements(Elements* elements,IoModel* iomodel,int analysis_counter,int analysis_type){/*{{{*/
|
|---|
| 84 |
|
|---|
| 85 | /*Fetch data needed: */
|
|---|
| 86 | int hydrology_model,frictionlaw;
|
|---|
| 87 | iomodel->FindConstant(&hydrology_model,"md.hydrology.model");
|
|---|
| 88 |
|
|---|
| 89 | /*Now, do we really want Sommers?*/
|
|---|
| 90 | if(hydrology_model!=HydrologysommersEnum) return;
|
|---|
| 91 |
|
|---|
| 92 | /*Update elements: */
|
|---|
| 93 | int counter=0;
|
|---|
| 94 | for(int i=0;i<iomodel->numberofelements;i++){
|
|---|
| 95 | if(iomodel->my_elements[i]){
|
|---|
| 96 | Element* element=(Element*)elements->GetObjectByOffset(counter);
|
|---|
| 97 | element->Update(i,iomodel,analysis_counter,analysis_type,P1Enum);
|
|---|
| 98 | counter++;
|
|---|
| 99 | }
|
|---|
| 100 | }
|
|---|
| 101 |
|
|---|
| 102 | iomodel->FetchDataToInput(elements,"md.geometry.thickness",ThicknessEnum);
|
|---|
| 103 | iomodel->FetchDataToInput(elements,"md.geometry.base",BaseEnum);
|
|---|
| 104 | if(iomodel->domaintype!=Domain2DhorizontalEnum){
|
|---|
| 105 | iomodel->FetchDataToInput(elements,"md.mesh.vertexonbase",MeshVertexonbaseEnum);
|
|---|
| 106 | iomodel->FetchDataToInput(elements,"md.mesh.vertexonsurface",MeshVertexonsurfaceEnum);
|
|---|
| 107 | }
|
|---|
| 108 | iomodel->FetchDataToInput(elements,"md.mask.ice_levelset",MaskIceLevelsetEnum);
|
|---|
| 109 | iomodel->FetchDataToInput(elements,"md.mask.groundedice_levelset",MaskGroundediceLevelsetEnum);
|
|---|
| 110 | iomodel->FetchDataToInput(elements,"md.basalforcings.groundedice_melting_rate",BasalforcingsGroundediceMeltingRateEnum);
|
|---|
| 111 | iomodel->FetchDataToInput(elements,"md.basalforcings.geothermalflux",BasalforcingsGeothermalfluxEnum);
|
|---|
| 112 | iomodel->FetchDataToInput(elements,"md.hydrology.head",HydrologyHeadEnum);
|
|---|
| 113 | iomodel->FetchDataToInput(elements,"md.hydrology.gap_height",HydrologyGapHeightEnum);
|
|---|
| 114 | iomodel->FetchDataToInput(elements,"md.hydrology.englacial_input",HydrologyEnglacialInputEnum);
|
|---|
| 115 | iomodel->FetchDataToInput(elements,"md.hydrology.moulin_input",HydrologyMoulinInputEnum);
|
|---|
| 116 | iomodel->FetchDataToInput(elements,"md.hydrology.bump_spacing",HydrologyBumpSpacingEnum);
|
|---|
| 117 | iomodel->FetchDataToInput(elements,"md.hydrology.bump_height",HydrologyBumpHeightEnum);
|
|---|
| 118 | iomodel->FetchDataToInput(elements,"md.hydrology.reynolds",HydrologyReynoldsEnum);
|
|---|
| 119 | iomodel->FetchDataToInput(elements,"md.hydrology.neumannflux",HydrologyNeumannfluxEnum);
|
|---|
| 120 | iomodel->FetchDataToInput(elements,"md.initialization.vx",VxEnum);
|
|---|
| 121 | iomodel->FetchDataToInput(elements,"md.initialization.vy",VyEnum);
|
|---|
| 122 | iomodel->FindConstant(&frictionlaw,"md.friction.law");
|
|---|
| 123 |
|
|---|
| 124 | /*Friction law variables*/
|
|---|
| 125 | switch(frictionlaw){
|
|---|
| 126 | case 1:
|
|---|
| 127 | iomodel->FetchDataToInput(elements,"md.friction.coefficient",FrictionCoefficientEnum);
|
|---|
| 128 | iomodel->FetchDataToInput(elements,"md.friction.p",FrictionPEnum);
|
|---|
| 129 | iomodel->FetchDataToInput(elements,"md.friction.q",FrictionQEnum);
|
|---|
| 130 | break;
|
|---|
| 131 | case 8:
|
|---|
| 132 | iomodel->FetchDataToInput(elements,"md.friction.coefficient",FrictionCoefficientEnum);
|
|---|
| 133 | break;
|
|---|
| 134 | default:
|
|---|
| 135 | _error_("Friction law "<< frictionlaw <<" not supported");
|
|---|
| 136 | }
|
|---|
| 137 | }/*}}}*/
|
|---|
| 138 | void HydrologySommersAnalysis::UpdateParameters(Parameters* parameters,IoModel* iomodel,int solution_enum,int analysis_enum){/*{{{*/
|
|---|
| 139 |
|
|---|
| 140 | /*retrieve some parameters: */
|
|---|
| 141 | int hydrology_model;
|
|---|
| 142 | int numoutputs;
|
|---|
| 143 | char** requestedoutputs = NULL;
|
|---|
| 144 | iomodel->FindConstant(&hydrology_model,"md.hydrology.model");
|
|---|
| 145 |
|
|---|
| 146 | /*Now, do we really want Sommers?*/
|
|---|
| 147 | if(hydrology_model!=HydrologysommersEnum) return;
|
|---|
| 148 |
|
|---|
| 149 | parameters->AddObject(new IntParam(HydrologyModelEnum,hydrology_model));
|
|---|
| 150 | parameters->AddObject(iomodel->CopyConstantObject("md.friction.law",FrictionLawEnum));
|
|---|
| 151 | parameters->AddObject(iomodel->CopyConstantObject("md.hydrology.relaxation",HydrologyRelaxationEnum));
|
|---|
| 152 | parameters->AddObject(iomodel->CopyConstantObject("md.hydrology.storage",HydrologyStorageEnum));
|
|---|
| 153 |
|
|---|
| 154 | /*Requested outputs*/
|
|---|
| 155 | iomodel->FindConstant(&requestedoutputs,&numoutputs,"md.hydrology.requested_outputs");
|
|---|
| 156 | parameters->AddObject(new IntParam(HydrologyNumRequestedOutputsEnum,numoutputs));
|
|---|
| 157 | if(numoutputs)parameters->AddObject(new StringArrayParam(HydrologyRequestedOutputsEnum,requestedoutputs,numoutputs));
|
|---|
| 158 | iomodel->DeleteData(&requestedoutputs,numoutputs,"md.hydrology.requested_outputs");
|
|---|
| 159 | }/*}}}*/
|
|---|
| 160 |
|
|---|
| 161 | /*Finite Element Analysis*/
|
|---|
| 162 | void HydrologySommersAnalysis::Core(FemModel* femmodel){/*{{{*/
|
|---|
| 163 | _error_("not implemented");
|
|---|
| 164 | }/*}}}*/
|
|---|
| 165 | ElementVector* HydrologySommersAnalysis::CreateDVector(Element* element){/*{{{*/
|
|---|
| 166 | /*Default, return NULL*/
|
|---|
| 167 | return NULL;
|
|---|
| 168 | }/*}}}*/
|
|---|
| 169 | ElementMatrix* HydrologySommersAnalysis::CreateJacobianMatrix(Element* element){/*{{{*/
|
|---|
| 170 | _error_("Not implemented");
|
|---|
| 171 | }/*}}}*/
|
|---|
| 172 | ElementMatrix* HydrologySommersAnalysis::CreateKMatrix(Element* element){/*{{{*/
|
|---|
| 173 |
|
|---|
| 174 | /*Intermediaries */
|
|---|
| 175 | IssmDouble Jdet;
|
|---|
| 176 | IssmDouble* xyz_list = NULL;
|
|---|
| 177 |
|
|---|
| 178 | /*Fetch number of nodes and dof for this finite element*/
|
|---|
| 179 | int numnodes = element->GetNumberOfNodes();
|
|---|
| 180 |
|
|---|
| 181 | /*Initialize Element vector and other vectors*/
|
|---|
| 182 | ElementMatrix* Ke = element->NewElementMatrix();
|
|---|
| 183 | IssmDouble* dbasis = xNew<IssmDouble>(2*numnodes);
|
|---|
| 184 | IssmDouble* basis = xNew<IssmDouble>(numnodes);
|
|---|
| 185 |
|
|---|
| 186 | /*Retrieve all inputs and parameters*/
|
|---|
| 187 | element->GetVerticesCoordinates(&xyz_list);
|
|---|
| 188 |
|
|---|
| 189 | /*Get conductivity from inputs*/
|
|---|
| 190 | IssmDouble conductivity = GetConductivity(element);
|
|---|
| 191 |
|
|---|
| 192 | /*Get englacial storage coefficient*/
|
|---|
| 193 | IssmDouble storage,dt;
|
|---|
| 194 | element->FindParam(&storage,HydrologyStorageEnum);
|
|---|
| 195 | element->FindParam(&dt,TimesteppingTimeStepEnum);
|
|---|
| 196 |
|
|---|
| 197 | /* Start looping on the number of gaussian points: */
|
|---|
| 198 | Gauss* gauss=element->NewGauss(1);
|
|---|
| 199 | for(int ig=gauss->begin();ig<gauss->end();ig++){
|
|---|
| 200 | gauss->GaussPoint(ig);
|
|---|
| 201 |
|
|---|
| 202 | element->JacobianDeterminant(&Jdet,xyz_list,gauss);
|
|---|
| 203 | element->NodalFunctionsDerivatives(dbasis,xyz_list,gauss);
|
|---|
| 204 | element->NodalFunctions(basis,gauss);
|
|---|
| 205 |
|
|---|
| 206 | for(int i=0;i<numnodes;i++){
|
|---|
| 207 | for(int j=0;j<numnodes;j++){
|
|---|
| 208 | Ke->values[i*numnodes+j] += conductivity*gauss->weight*Jdet*(dbasis[0*numnodes+i]*dbasis[0*numnodes+j] + dbasis[1*numnodes+i]*dbasis[1*numnodes+j])
|
|---|
| 209 | + gauss->weight*Jdet*storage/dt*basis[i]*basis[j];
|
|---|
| 210 | }
|
|---|
| 211 | }
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | /*Clean up and return*/
|
|---|
| 215 | xDelete<IssmDouble>(xyz_list);
|
|---|
| 216 | xDelete<IssmDouble>(basis);
|
|---|
| 217 | xDelete<IssmDouble>(dbasis);
|
|---|
| 218 | delete gauss;
|
|---|
| 219 | return Ke;
|
|---|
| 220 | }/*}}}*/
|
|---|
| 221 | ElementVector* HydrologySommersAnalysis::CreatePVector(Element* element){/*{{{*/
|
|---|
| 222 |
|
|---|
| 223 | /*Skip if water or ice shelf element*/
|
|---|
| 224 | if(element->IsFloating()) return NULL;
|
|---|
| 225 |
|
|---|
| 226 | /*Intermediaries */
|
|---|
| 227 | IssmDouble Jdet,meltrate,G,dh[2],B,A,n;
|
|---|
| 228 | IssmDouble gap,bed,thickness,head,ieb,head_old;
|
|---|
| 229 | IssmDouble lr,br,vx,vy,beta;
|
|---|
| 230 | IssmDouble alpha2,frictionheat;
|
|---|
| 231 | IssmDouble PMPheat,dpressure_water[2],dbed[2];
|
|---|
| 232 | IssmDouble* xyz_list = NULL;
|
|---|
| 233 |
|
|---|
| 234 | /*Fetch number of nodes and dof for this finite element*/
|
|---|
| 235 | int numnodes = element->GetNumberOfNodes();
|
|---|
| 236 |
|
|---|
| 237 | /*Initialize Element vector and other vectors*/
|
|---|
| 238 | ElementVector* pe = element->NewElementVector();
|
|---|
| 239 | IssmDouble* basis = xNew<IssmDouble>(numnodes);
|
|---|
| 240 |
|
|---|
| 241 | /*Retrieve all inputs and parameters*/
|
|---|
| 242 | element->GetVerticesCoordinates(&xyz_list);
|
|---|
| 243 | IssmDouble latentheat = element->GetMaterialParameter(MaterialsLatentheatEnum);
|
|---|
| 244 | IssmDouble g = element->GetMaterialParameter(ConstantsGEnum);
|
|---|
| 245 | IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
|
|---|
| 246 | IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoFreshwaterEnum);
|
|---|
| 247 | Input* geothermalflux_input = element->GetInput(BasalforcingsGeothermalfluxEnum);_assert_(geothermalflux_input);
|
|---|
| 248 | Input* head_input = element->GetInput(HydrologyHeadEnum); _assert_(head_input);
|
|---|
| 249 | Input* gap_input = element->GetInput(HydrologyGapHeightEnum); _assert_(gap_input);
|
|---|
| 250 | Input* thickness_input = element->GetInput(ThicknessEnum); _assert_(thickness_input);
|
|---|
| 251 | Input* base_input = element->GetInput(BaseEnum); _assert_(base_input);
|
|---|
| 252 | Input* B_input = element->GetInput(MaterialsRheologyBEnum); _assert_(B_input);
|
|---|
| 253 | Input* n_input = element->GetInput(MaterialsRheologyNEnum); _assert_(n_input);
|
|---|
| 254 | Input* englacial_input = element->GetInput(HydrologyEnglacialInputEnum); _assert_(englacial_input);
|
|---|
| 255 | Input* vx_input = element->GetInput(VxEnum); _assert_(vx_input);
|
|---|
| 256 | Input* vy_input = element->GetInput(VyEnum); _assert_(vy_input);
|
|---|
| 257 | Input* lr_input = element->GetInput(HydrologyBumpSpacingEnum); _assert_(lr_input);
|
|---|
| 258 | Input* br_input = element->GetInput(HydrologyBumpHeightEnum); _assert_(br_input);
|
|---|
| 259 | Input* headold_input = element->GetInput(HydrologyHeadOldEnum); _assert_(headold_input);
|
|---|
| 260 |
|
|---|
| 261 | /*Get conductivity from inputs*/
|
|---|
| 262 | IssmDouble conductivity = GetConductivity(element);
|
|---|
| 263 |
|
|---|
| 264 | /*Get englacial storage coefficient*/
|
|---|
| 265 | IssmDouble storage,dt;
|
|---|
| 266 | element->FindParam(&storage,HydrologyStorageEnum);
|
|---|
| 267 | element->FindParam(&dt,TimesteppingTimeStepEnum);
|
|---|
| 268 |
|
|---|
| 269 | /*Build friction element, needed later: */
|
|---|
| 270 | Friction* friction=new Friction(element,2);
|
|---|
| 271 |
|
|---|
| 272 | /* Start looping on the number of gaussian points: */
|
|---|
| 273 | Gauss* gauss=element->NewGauss(2);
|
|---|
| 274 | for(int ig=gauss->begin();ig<gauss->end();ig++){
|
|---|
| 275 | gauss->GaussPoint(ig);
|
|---|
| 276 |
|
|---|
| 277 | element->JacobianDeterminant(&Jdet,xyz_list,gauss);
|
|---|
| 278 | element->NodalFunctions(basis,gauss);
|
|---|
| 279 | geothermalflux_input->GetInputValue(&G,gauss);
|
|---|
| 280 | base_input->GetInputValue(&bed,gauss);
|
|---|
| 281 | base_input->GetInputDerivativeValue(&dbed[0],xyz_list,gauss);
|
|---|
| 282 | thickness_input->GetInputValue(&thickness,gauss);
|
|---|
| 283 | gap_input->GetInputValue(&gap,gauss);
|
|---|
| 284 | head_input->GetInputValue(&head,gauss);
|
|---|
| 285 | head_input->GetInputDerivativeValue(&dh[0],xyz_list,gauss);
|
|---|
| 286 | englacial_input->GetInputValue(&ieb,gauss);
|
|---|
| 287 | lr_input->GetInputValue(&lr,gauss);
|
|---|
| 288 | br_input->GetInputValue(&br,gauss);
|
|---|
| 289 | vx_input->GetInputValue(&vx,gauss);
|
|---|
| 290 | vy_input->GetInputValue(&vy,gauss);
|
|---|
| 291 | headold_input->GetInputValue(&head_old,gauss);
|
|---|
| 292 |
|
|---|
| 293 | /*Get ice A parameter*/
|
|---|
| 294 | B_input->GetInputValue(&B,gauss);
|
|---|
| 295 | n_input->GetInputValue(&n,gauss);
|
|---|
| 296 | A=pow(B,-n);
|
|---|
| 297 |
|
|---|
| 298 | /*Compute beta term*/
|
|---|
| 299 | if(gap<br)
|
|---|
| 300 | beta = (br-gap)/lr;
|
|---|
| 301 | else
|
|---|
| 302 | beta = 0.;
|
|---|
| 303 |
|
|---|
| 304 | /*Compute frictional heat flux*/
|
|---|
| 305 | friction->GetAlpha2(&alpha2,gauss);
|
|---|
| 306 | vx_input->GetInputValue(&vx,gauss);
|
|---|
| 307 | vy_input->GetInputValue(&vy,gauss);
|
|---|
| 308 | frictionheat=alpha2*(vx*vx+vy*vy);
|
|---|
| 309 |
|
|---|
| 310 | /*Get water and ice pressures*/
|
|---|
| 311 | IssmDouble pressure_ice = rho_ice*g*thickness; _assert_(pressure_ice>0.);
|
|---|
| 312 | IssmDouble pressure_water = rho_water*g*(head-bed);
|
|---|
| 313 | if(pressure_water>pressure_ice) pressure_water = pressure_ice;
|
|---|
| 314 |
|
|---|
| 315 | /*Get water pressure from previous time step to use in lagged creep term*/
|
|---|
| 316 | IssmDouble pressure_water_old = rho_water*g*(head_old-bed);
|
|---|
| 317 | if(pressure_water_old>pressure_ice) pressure_water_old = pressure_ice;
|
|---|
| 318 |
|
|---|
| 319 | /*Compute change in sensible heat due to changes in pressure melting point*/
|
|---|
| 320 | dpressure_water[0] = rho_water*g*(dh[0] - dbed[0]);
|
|---|
| 321 | dpressure_water[1] = rho_water*g*(dh[1] - dbed[1]);
|
|---|
| 322 | PMPheat=-CT*CW*conductivity*(dh[0]*dpressure_water[0]+dh[1]*dpressure_water[1]);
|
|---|
| 323 |
|
|---|
| 324 | meltrate = 1/latentheat*(G+frictionheat+rho_water*g*conductivity*(dh[0]*dh[0]+dh[1]*dh[1])-PMPheat);
|
|---|
| 325 | _assert_(meltrate>0.);
|
|---|
| 326 |
|
|---|
| 327 | for(int i=0;i<numnodes;i++) pe->values[i]+=Jdet*gauss->weight*
|
|---|
| 328 | (
|
|---|
| 329 | meltrate*(1/rho_water-1/rho_ice)
|
|---|
| 330 | +A*pow(fabs(pressure_ice - pressure_water),n-1)*(pressure_ice - pressure_water)*gap
|
|---|
| 331 | -beta*sqrt(vx*vx+vy*vy)
|
|---|
| 332 | +ieb
|
|---|
| 333 | +storage*head_old/dt
|
|---|
| 334 | )*basis[i];
|
|---|
| 335 | }
|
|---|
| 336 | /*Clean up and return*/
|
|---|
| 337 | xDelete<IssmDouble>(xyz_list);
|
|---|
| 338 | xDelete<IssmDouble>(basis);
|
|---|
| 339 | delete friction;
|
|---|
| 340 | delete gauss;
|
|---|
| 341 | return pe;
|
|---|
| 342 | }/*}}}*/
|
|---|
| 343 | void HydrologySommersAnalysis::GetSolutionFromInputs(Vector<IssmDouble>* solution,Element* element){/*{{{*/
|
|---|
| 344 | element->GetSolutionFromInputsOneDof(solution,HydrologyHeadEnum);
|
|---|
| 345 | }/*}}}*/
|
|---|
| 346 | void HydrologySommersAnalysis::GradientJ(Vector<IssmDouble>* gradient,Element* element,int control_type,int control_index){/*{{{*/
|
|---|
| 347 | _error_("Not implemented yet");
|
|---|
| 348 | }/*}}}*/
|
|---|
| 349 | void HydrologySommersAnalysis::InputUpdateFromSolution(IssmDouble* solution,Element* element){/*{{{*/
|
|---|
| 350 |
|
|---|
| 351 | /*Intermediary*/
|
|---|
| 352 | IssmDouble dh[3];
|
|---|
| 353 | int* doflist = NULL;
|
|---|
| 354 | IssmDouble* xyz_list = NULL;
|
|---|
| 355 |
|
|---|
| 356 | /*Get gravity from parameters*/
|
|---|
| 357 | IssmDouble g = element->GetMaterialParameter(ConstantsGEnum);
|
|---|
| 358 |
|
|---|
| 359 | /*Fetch number of nodes for this finite element*/
|
|---|
| 360 | int numnodes = element->GetNumberOfNodes();
|
|---|
| 361 |
|
|---|
| 362 | /*Fetch dof list and allocate solution vector*/
|
|---|
| 363 | element->GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
|
|---|
| 364 | IssmDouble* values = xNew<IssmDouble>(numnodes);
|
|---|
| 365 |
|
|---|
| 366 | /*Get thickness and base on nodes to apply cap on water head*/
|
|---|
| 367 | IssmDouble* eff_pressure = xNew<IssmDouble>(numnodes);
|
|---|
| 368 | IssmDouble* thickness = xNew<IssmDouble>(numnodes);
|
|---|
| 369 | IssmDouble* bed = xNew<IssmDouble>(numnodes);
|
|---|
| 370 | IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
|
|---|
| 371 | IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoFreshwaterEnum);
|
|---|
| 372 | element->GetInputListOnNodes(&thickness[0],ThicknessEnum);
|
|---|
| 373 | element->GetInputListOnNodes(&bed[0],BaseEnum);
|
|---|
| 374 |
|
|---|
| 375 | /*Get head from previous time-step and under-relaxation coefficient to use in under-relaxation for nonlinear convergence*/
|
|---|
| 376 | IssmDouble* head_old = xNew<IssmDouble>(numnodes);
|
|---|
| 377 | element->GetInputListOnNodes(&head_old[0],HydrologyHeadEnum);
|
|---|
| 378 | IssmDouble relaxation;
|
|---|
| 379 | element->FindParam(&relaxation,HydrologyRelaxationEnum);
|
|---|
| 380 |
|
|---|
| 381 | /*Use the dof list to index into the solution vector: */
|
|---|
| 382 | for(int i=0;i<numnodes;i++){
|
|---|
| 383 | values[i]=solution[doflist[i]];
|
|---|
| 384 |
|
|---|
| 385 | /*make sure that p_water<p_ice -> h<rho_i H/rho_w + zb*/
|
|---|
| 386 | if(values[i]>rho_ice*thickness[i]/rho_water+bed[i]){
|
|---|
| 387 | values[i] = rho_ice*thickness[i]/rho_water+bed[i];
|
|---|
| 388 | }
|
|---|
| 389 |
|
|---|
| 390 | /*Make sure that negative pressure is not allowed*/
|
|---|
| 391 | // if(values[i]<bed[i]){
|
|---|
| 392 | // values[i] = bed[i];
|
|---|
| 393 | // }
|
|---|
| 394 |
|
|---|
| 395 | /*Under-relaxation*/
|
|---|
| 396 | values[i] = head_old[i] - relaxation*(head_old[i]-values[i]);
|
|---|
| 397 |
|
|---|
| 398 | /*Calculate effective pressure*/
|
|---|
| 399 | eff_pressure[i] = rho_ice*g*thickness[i] - rho_water*g*(values[i]-bed[i]);
|
|---|
| 400 |
|
|---|
| 401 | if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
|
|---|
| 402 | if(xIsInf<IssmDouble>(values[i])) _error_("Inf found in solution vector");
|
|---|
| 403 | }
|
|---|
| 404 |
|
|---|
| 405 | /*Add input to the element: */
|
|---|
| 406 | element->AddInput(HydrologyHeadEnum,values,element->GetElementType());
|
|---|
| 407 | element->AddInput(EffectivePressureEnum,eff_pressure,P1Enum);
|
|---|
| 408 |
|
|---|
| 409 | /*Update reynolds number according to new solution*/
|
|---|
| 410 | element->GetVerticesCoordinates(&xyz_list);
|
|---|
| 411 | Input* head_input = element->GetInput(HydrologyHeadEnum);_assert_(head_input);
|
|---|
| 412 | head_input->GetInputDerivativeAverageValue(&dh[0],xyz_list);
|
|---|
| 413 | IssmDouble conductivity = GetConductivity(element);
|
|---|
| 414 |
|
|---|
| 415 | IssmDouble reynolds = conductivity*sqrt(dh[0]*dh[0]+dh[1]*dh[1])/NU;
|
|---|
| 416 | element->AddInput(HydrologyReynoldsEnum,&reynolds,P0Enum);
|
|---|
| 417 |
|
|---|
| 418 | /*Free resources:*/
|
|---|
| 419 | xDelete<IssmDouble>(values);
|
|---|
| 420 | xDelete<IssmDouble>(thickness);
|
|---|
| 421 | xDelete<IssmDouble>(bed);
|
|---|
| 422 | xDelete<IssmDouble>(xyz_list);
|
|---|
| 423 | xDelete<int>(doflist);
|
|---|
| 424 | xDelete<IssmDouble>(eff_pressure);
|
|---|
| 425 | xDelete<IssmDouble>(head_old);
|
|---|
| 426 | }/*}}}*/
|
|---|
| 427 | void HydrologySommersAnalysis::UpdateConstraints(FemModel* femmodel){/*{{{*/
|
|---|
| 428 | /*Default, do nothing*/
|
|---|
| 429 | return;
|
|---|
| 430 | }/*}}}*/
|
|---|
| 431 |
|
|---|
| 432 | /*Additional methods*/
|
|---|
| 433 | IssmDouble HydrologySommersAnalysis::GetConductivity(Element* element){/*{{{*/
|
|---|
| 434 |
|
|---|
| 435 | /*Intermediaries */
|
|---|
| 436 | IssmDouble gap,reynolds;
|
|---|
| 437 |
|
|---|
| 438 | /*Get gravity from parameters*/
|
|---|
| 439 | IssmDouble g = element->GetMaterialParameter(ConstantsGEnum);
|
|---|
| 440 |
|
|---|
| 441 | /*Get Reynolds and gap average values*/
|
|---|
| 442 | Input* reynolds_input = element->GetInput(HydrologyReynoldsEnum); _assert_(reynolds_input);
|
|---|
| 443 | Input* gap_input = element->GetInput(HydrologyGapHeightEnum); _assert_(gap_input);
|
|---|
| 444 | reynolds_input->GetInputAverage(&reynolds);
|
|---|
| 445 | gap_input->GetInputAverage(&gap);
|
|---|
| 446 |
|
|---|
| 447 | /*Compute conductivity*/
|
|---|
| 448 | IssmDouble conductivity = pow(gap,3)*g/(12.*NU*(1+OMEGA*reynolds));
|
|---|
| 449 | _assert_(conductivity>0);
|
|---|
| 450 |
|
|---|
| 451 | /*Clean up and return*/
|
|---|
| 452 | return conductivity;
|
|---|
| 453 | }/*}}}*/
|
|---|
| 454 | void HydrologySommersAnalysis::UpdateGapHeight(FemModel* femmodel){/*{{{*/
|
|---|
| 455 |
|
|---|
| 456 |
|
|---|
| 457 | for(int j=0;j<femmodel->elements->Size();j++){
|
|---|
| 458 | Element* element=(Element*)femmodel->elements->GetObjectByOffset(j);
|
|---|
| 459 | UpdateGapHeight(element);
|
|---|
| 460 | }
|
|---|
| 461 |
|
|---|
| 462 | }/*}}}*/
|
|---|
| 463 | void HydrologySommersAnalysis::UpdateGapHeight(Element* element){/*{{{*/
|
|---|
| 464 |
|
|---|
| 465 | /*Skip if water or ice shelf element*/
|
|---|
| 466 | if(element->IsFloating()) return;
|
|---|
| 467 |
|
|---|
| 468 | /*Intermediaries */
|
|---|
| 469 | IssmDouble newgap = 0.;
|
|---|
| 470 | IssmDouble Jdet,meltrate,G,dh[2],B,A,n,dt;
|
|---|
| 471 | IssmDouble gap,bed,thickness,head,ieb;
|
|---|
| 472 | IssmDouble lr,br,vx,vy,beta;
|
|---|
| 473 | IssmDouble alpha2,frictionheat;
|
|---|
| 474 | IssmDouble* xyz_list = NULL;
|
|---|
| 475 | IssmDouble dpressure_water[2],dbed[2],PMPheat;
|
|---|
| 476 | IssmDouble q = 0.;
|
|---|
| 477 | IssmDouble channelization = 0.;
|
|---|
| 478 |
|
|---|
| 479 | /*Retrieve all inputs and parameters*/
|
|---|
| 480 | element->GetVerticesCoordinates(&xyz_list);
|
|---|
| 481 | element->FindParam(&dt,TimesteppingTimeStepEnum);
|
|---|
| 482 | IssmDouble latentheat = element->GetMaterialParameter(MaterialsLatentheatEnum);
|
|---|
| 483 | IssmDouble g = element->GetMaterialParameter(ConstantsGEnum);
|
|---|
| 484 | IssmDouble rho_ice = element->GetMaterialParameter(MaterialsRhoIceEnum);
|
|---|
| 485 | IssmDouble rho_water = element->GetMaterialParameter(MaterialsRhoFreshwaterEnum);
|
|---|
| 486 | Input* geothermalflux_input = element->GetInput(BasalforcingsGeothermalfluxEnum);_assert_(geothermalflux_input);
|
|---|
| 487 | Input* head_input = element->GetInput(HydrologyHeadEnum); _assert_(head_input);
|
|---|
| 488 | Input* gap_input = element->GetInput(HydrologyGapHeightEnum); _assert_(gap_input);
|
|---|
| 489 | Input* thickness_input = element->GetInput(ThicknessEnum); _assert_(thickness_input);
|
|---|
| 490 | Input* base_input = element->GetInput(BaseEnum); _assert_(base_input);
|
|---|
| 491 | Input* B_input = element->GetInput(MaterialsRheologyBEnum); _assert_(B_input);
|
|---|
| 492 | Input* n_input = element->GetInput(MaterialsRheologyNEnum); _assert_(n_input);
|
|---|
| 493 | Input* englacial_input = element->GetInput(HydrologyEnglacialInputEnum); _assert_(englacial_input);
|
|---|
| 494 | Input* vx_input = element->GetInput(VxEnum); _assert_(vx_input);
|
|---|
| 495 | Input* vy_input = element->GetInput(VyEnum); _assert_(vy_input);
|
|---|
| 496 | Input* lr_input = element->GetInput(HydrologyBumpSpacingEnum); _assert_(lr_input);
|
|---|
| 497 | Input* br_input = element->GetInput(HydrologyBumpHeightEnum); _assert_(br_input);
|
|---|
| 498 |
|
|---|
| 499 | /*Get conductivity from inputs*/
|
|---|
| 500 | IssmDouble conductivity = GetConductivity(element);
|
|---|
| 501 |
|
|---|
| 502 | /*Build friction element, needed later: */
|
|---|
| 503 | Friction* friction=new Friction(element,2);
|
|---|
| 504 |
|
|---|
| 505 | /*Keep track of weights*/
|
|---|
| 506 | IssmDouble totalweights=0.;
|
|---|
| 507 |
|
|---|
| 508 | /* Start looping on the number of gaussian points: */
|
|---|
| 509 | Gauss* gauss=element->NewGauss(2);
|
|---|
| 510 | for(int ig=gauss->begin();ig<gauss->end();ig++){
|
|---|
| 511 | gauss->GaussPoint(ig);
|
|---|
| 512 |
|
|---|
| 513 | element->JacobianDeterminant(&Jdet,xyz_list,gauss);
|
|---|
| 514 |
|
|---|
| 515 | geothermalflux_input->GetInputValue(&G,gauss);
|
|---|
| 516 | base_input->GetInputValue(&bed,gauss);
|
|---|
| 517 | base_input->GetInputDerivativeValue(&dbed[0],xyz_list,gauss);
|
|---|
| 518 | thickness_input->GetInputValue(&thickness,gauss);
|
|---|
| 519 | gap_input->GetInputValue(&gap,gauss);
|
|---|
| 520 | head_input->GetInputValue(&head,gauss);
|
|---|
| 521 | head_input->GetInputDerivativeValue(&dh[0],xyz_list,gauss);
|
|---|
| 522 | englacial_input->GetInputValue(&ieb,gauss);
|
|---|
| 523 | lr_input->GetInputValue(&lr,gauss);
|
|---|
| 524 | br_input->GetInputValue(&br,gauss);
|
|---|
| 525 | vx_input->GetInputValue(&vx,gauss);
|
|---|
| 526 | vy_input->GetInputValue(&vy,gauss);
|
|---|
| 527 |
|
|---|
| 528 | /*Get ice A parameter*/
|
|---|
| 529 | B_input->GetInputValue(&B,gauss);
|
|---|
| 530 | n_input->GetInputValue(&n,gauss);
|
|---|
| 531 | A=pow(B,-n);
|
|---|
| 532 |
|
|---|
| 533 | /*Compute beta term*/
|
|---|
| 534 | if(gap<br)
|
|---|
| 535 | beta = (br-gap)/lr;
|
|---|
| 536 | else
|
|---|
| 537 | beta = 0.;
|
|---|
| 538 |
|
|---|
| 539 | /*Compute frictional heat flux*/
|
|---|
| 540 | friction->GetAlpha2(&alpha2,gauss);
|
|---|
| 541 | vx_input->GetInputValue(&vx,gauss);
|
|---|
| 542 | vy_input->GetInputValue(&vy,gauss);
|
|---|
| 543 | frictionheat=alpha2*(vx*vx+vy*vy);
|
|---|
| 544 |
|
|---|
| 545 | /*Get water and ice pressures*/
|
|---|
| 546 | IssmDouble pressure_ice = rho_ice*g*thickness; _assert_(pressure_ice>0.);
|
|---|
| 547 | IssmDouble pressure_water = rho_water*g*(head-bed);
|
|---|
| 548 | if(pressure_water>pressure_ice) pressure_water = pressure_ice;
|
|---|
| 549 |
|
|---|
| 550 | /* Compute change in sensible heat due to changes in pressure melting point*/
|
|---|
| 551 | dpressure_water[0] = rho_water*g*(dh[0] - dbed[0]);
|
|---|
| 552 | dpressure_water[1] = rho_water*g*(dh[1] - dbed[1]);
|
|---|
| 553 | PMPheat=-CT*CW*conductivity*(dh[0]*dpressure_water[0]+dh[1]*dpressure_water[1]);
|
|---|
| 554 |
|
|---|
| 555 | meltrate = 1/latentheat*(G+frictionheat+rho_water*g*conductivity*(dh[0]*dh[0]+dh[1]*dh[1])-PMPheat);
|
|---|
| 556 | _assert_(meltrate>0.);
|
|---|
| 557 |
|
|---|
| 558 | newgap += gauss->weight*Jdet*(gap+dt*(
|
|---|
| 559 | meltrate/rho_ice
|
|---|
| 560 | -A*pow(fabs(pressure_ice-pressure_water),n-1)*(pressure_ice-pressure_water)*gap
|
|---|
| 561 | +beta*sqrt(vx*vx+vy*vy)
|
|---|
| 562 | ));
|
|---|
| 563 | totalweights +=gauss->weight*Jdet;
|
|---|
| 564 |
|
|---|
| 565 | /* Compute basal water flux */
|
|---|
| 566 | q += gauss->weight*Jdet*(conductivity*sqrt(dh[0]*dh[0]+dh[1]*dh[1]));
|
|---|
| 567 |
|
|---|
| 568 | /* Compute "degree of channelization" (ratio of melt opening to opening by sliding) */
|
|---|
| 569 | channelization += gauss->weight*Jdet*(meltrate/rho_ice/(meltrate/rho_ice+beta*sqrt(vx*vx+vy*vy)));
|
|---|
| 570 | }
|
|---|
| 571 |
|
|---|
| 572 | /*Divide by connectivity*/
|
|---|
| 573 | newgap = newgap/totalweights;
|
|---|
| 574 | IssmDouble mingap = 1e-6;
|
|---|
| 575 | if(newgap<mingap) newgap=mingap;
|
|---|
| 576 |
|
|---|
| 577 | /*Limit gap height to grow to surface*/
|
|---|
| 578 | if(newgap>thickness)
|
|---|
| 579 | newgap = thickness;
|
|---|
| 580 |
|
|---|
| 581 | /*Add new gap as an input*/
|
|---|
| 582 | element->AddInput(HydrologyGapHeightEnum,&newgap,P0Enum);
|
|---|
| 583 |
|
|---|
| 584 | /*Divide by connectivity, add basal flux as an input*/
|
|---|
| 585 | q = q/totalweights;
|
|---|
| 586 | element->AddInput(HydrologyBasalFluxEnum,&q,P0Enum);
|
|---|
| 587 |
|
|---|
| 588 | /* Divide by connectivity, add degree of channelization as an input */
|
|---|
| 589 | channelization = channelization/totalweights;
|
|---|
| 590 | element->AddInput(DegreeOfChannelizationEnum,&channelization,P0Enum);
|
|---|
| 591 |
|
|---|
| 592 | /*Clean up and return*/
|
|---|
| 593 | xDelete<IssmDouble>(xyz_list);
|
|---|
| 594 | delete friction;
|
|---|
| 595 | delete gauss;
|
|---|
| 596 | }/*}}}*/
|
|---|