Changeset 6410


Ignore:
Timestamp:
10/25/10 08:08:10 (14 years ago)
Author:
Mathieu Morlighem
Message:

Routine reordering

Location:
issm/trunk/src/c/objects/Elements
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk/src/c/objects/Elements/Penta.cpp

    r6397 r6410  
    2727#define NDOF4 4
    2828
    29 /*Penta constructors and destructor*/
     29/*Constructors/destructor/copy*/
    3030/*FUNCTION Penta::Penta(){{{1*/
    3131Penta::Penta(){
     
    8585}
    8686/*}}}*/
    87 
    88 /*Object virtual functions definitions: */
    8987/*FUNCTION Penta::copy {{{1*/
    9088Object* Penta::copy() {
     
    135133}
    136134/*}}}*/
    137 /*FUNCTION Penta::DeepEcho{{{1*/
    138 void Penta::DeepEcho(void){
    139 
    140         int i;
    141        
    142         printf("Penta:\n");
    143         printf("   id: %i\n",id);
    144         nodes[0]->DeepEcho();
    145         nodes[1]->DeepEcho();
    146         nodes[2]->DeepEcho();
    147         nodes[3]->DeepEcho();
    148         nodes[4]->DeepEcho();
    149         nodes[5]->DeepEcho();
    150         matice->DeepEcho();
    151         matpar->DeepEcho();
    152         printf("   neighbor ids: %i-%i\n",neighbors[0]->Id(),neighbors[1]->Id());
    153         printf("   parameters\n");
    154         parameters->DeepEcho();
    155         printf("   inputs\n");
    156         inputs->DeepEcho();
    157         printf("   results\n");
    158         results->DeepEcho();
    159         return;
    160 }
    161 /*}}}*/
    162 /*FUNCTION Penta::Demarshall {{{1*/
    163 void  Penta::Demarshall(char** pmarshalled_dataset){
    164 
    165         char* marshalled_dataset=NULL;
    166         int   i;
    167         int flaghook;
    168 
    169         /*recover marshalled_dataset: */
    170         marshalled_dataset=*pmarshalled_dataset;
    171 
    172         /*this time, no need to get enum type, the pointer directly points to the beginning of the
    173          *object data (thanks to DataSet::Demarshall):*/
    174         memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
    175         memcpy(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
    176 
    177         /*demarshall Ref: */
    178         this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
    179         for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
    180 
    181         /*allocate dynamic memory: */
    182         this->hnodes=new Hook*[this->numanalyses];
    183         /*demarshall hooks: */
    184         for(i=0;i<numanalyses;i++){
    185                 memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
    186                 if(flaghook){ // there is a hook so demarshall it
    187                         hnodes[i]=new Hook();
    188                         hnodes[i]->Demarshall(&marshalled_dataset);
    189                 }
    190                 else hnodes[i]=NULL; //There is no hook so it is NULL
    191         }
    192         hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
    193         hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
    194         hneighbors=new Hook(); hneighbors->Demarshall(&marshalled_dataset);
    195 
    196         /*pointers are garbage, until configuration is carried out: */
    197         nodes=NULL;
    198         matice=NULL;
    199         matpar=NULL;
    200         neighbors=NULL;
    201        
    202         /*demarshall inputs and results: */
    203         inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset);
    204         results=(Results*)DataSetDemarshallRaw(&marshalled_dataset);
    205 
    206         /*parameters: may not exist even yet, so let Configure handle it: */
    207         this->parameters=NULL;
    208 
    209         /*return: */
    210         *pmarshalled_dataset=marshalled_dataset;
    211         return;
    212 }
    213 /*}}}*/
    214 /*FUNCTION Penta::Echo{{{1*/
    215 
    216 void Penta::Echo(void){
    217         this->DeepEcho();
    218 }
    219 /*}}}*/
    220 /*FUNCTION Penta::Enum {{{1*/
    221 int Penta::Enum(void){
    222 
    223         return PentaEnum;
    224 
    225 }
    226 /*}}}*/
    227 /*FUNCTION Penta::Id {{{1*/
    228 int    Penta::Id(void){
    229         return id;
    230 }
    231 /*}}}*/
     135
     136/*Marshall*/
    232137/*FUNCTION Penta::Marshall {{{1*/
    233138void  Penta::Marshall(char** pmarshalled_dataset){
     
    321226}
    322227/*}}}*/
    323 /*FUNCTION Penta::MyRank {{{1*/
    324 int    Penta::MyRank(void){
    325         extern int my_rank;
    326         return my_rank;
    327 }
    328 /*}}}*/
    329 
    330 /*Update virtual functions definitions: */
    331 /*FUNCTION Penta::InputUpdateFromConstant(bool value, int name);{{{1*/
    332 void  Penta::InputUpdateFromConstant(bool constant, int name){
    333 
    334         /*Check that name is an element input*/
    335         if (!IsInput(name)) return;
    336 
    337         /*update input*/
    338         this->inputs->AddInput(new BoolInput(name,constant));
    339 }
    340 /*}}}*/
    341 /*FUNCTION Penta::InputUpdateFromConstant(double value, int name);{{{1*/
    342 void  Penta::InputUpdateFromConstant(double constant, int name){
    343         /*Check that name is an element input*/
    344         if (!IsInput(name)) return;
    345 
    346         /*update input*/
    347         this->inputs->AddInput(new DoubleInput(name,constant));
    348 }
    349 /*}}}*/
    350 /*FUNCTION Penta::InputUpdateFromConstant(int value, int name);{{{1*/
    351 void  Penta::InputUpdateFromConstant(int constant, int name){
    352         /*Check that name is an element input*/
    353         if (!IsInput(name)) return;
    354 
    355         /*update input*/
    356         this->inputs->AddInput(new IntInput(name,constant));
    357 }
    358 /*}}}*/
    359 /*FUNCTION Penta::InputUpdateFromSolution {{{1*/
    360 void  Penta::InputUpdateFromSolution(double* solution){
    361 
    362         int analysis_type;
    363 
    364         /*retreive parameters: */
    365         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    366 
    367         /*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
    368         if (analysis_type==DiagnosticHorizAnalysisEnum){
    369                 InputUpdateFromSolutionDiagnosticHoriz( solution);
    370         }
    371         else if (analysis_type==DiagnosticHutterAnalysisEnum){
    372                 InputUpdateFromSolutionDiagnosticHutter( solution);
    373         }
    374         else if (analysis_type==DiagnosticVertAnalysisEnum){
    375                 InputUpdateFromSolutionDiagnosticVert( solution);
    376         }
    377         else if (analysis_type==AdjointHorizAnalysisEnum){
    378                 int approximation;
    379                 inputs->GetParameterValue(&approximation,ApproximationEnum);
    380                 if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
    381                         InputUpdateFromSolutionAdjointStokes( solution);
    382                 }
    383                 else{
    384                         InputUpdateFromSolutionAdjointHoriz( solution);
    385                 }
    386         }
    387         else if (analysis_type==BedSlopeXAnalysisEnum){
    388                 InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeXEnum);
    389         }
    390         else if (analysis_type==BedSlopeYAnalysisEnum){
    391                 InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeYEnum);
    392         }
    393         else if (analysis_type==SurfaceSlopeXAnalysisEnum){
    394                 InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeXEnum);
    395         }
    396         else if (analysis_type==SurfaceSlopeYAnalysisEnum){
    397                 InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeYEnum);
    398         }
    399         else if (analysis_type==PrognosticAnalysisEnum){
    400                 InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
    401         }
    402         else if (analysis_type==BalancedthicknessAnalysisEnum){
    403                 InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
    404         }
    405         else if (analysis_type==BalancedvelocitiesAnalysisEnum){
    406                 InputUpdateFromSolutionOneDofCollapsed(solution,VelEnum);
    407         }
    408         else if (analysis_type==ThermalAnalysisEnum){
    409                 InputUpdateFromSolutionThermal( solution);
    410         }
    411         else if (analysis_type==MeltingAnalysisEnum){
    412                 InputUpdateFromSolutionOneDof(solution,MeltingRateEnum);
    413         }
    414         else{
    415                 ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
    416         }
    417 }
    418 /*}}}*/
    419 /*FUNCTION Penta::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
    420 void  Penta::InputUpdateFromVector(double* vector, int name, int type){
    421 
    422         /*Check that name is an element input*/
    423         if (!IsInput(name)) return;
    424 
    425         /*Penta update B in InputUpdateFromSolutionThermal, so don't look for B update here.*/
    426 
    427         switch(type){
    428 
    429                 case VertexEnum:
    430 
    431                         /*New PentaVertexInpu*/
    432                         double values[6];
    433 
    434                         /*Get values on the 6 vertices*/
    435                         for (int i=0;i<6;i++){
    436                                 values[i]=vector[this->nodes[i]->GetVertexDof()];
    437                         }
    438 
    439                         /*update input*/
    440                         this->inputs->AddInput(new PentaVertexInput(name,values));
    441                         return;
    442 
    443                 default:
    444 
    445                         ISSMERROR("type %i (%s) not implemented yet",type,EnumToString(type));
    446         }
    447 }
    448 /*}}}*/
    449 /*FUNCTION Penta::InputUpdateFromVector(int* vector, int name, int type);{{{1*/
    450 void  Penta::InputUpdateFromVector(int* vector, int name, int type){
    451         ISSMERROR(" not supported yet!");
    452 }
    453 /*}}}*/
    454 /*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{1*/
    455 void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
    456         ISSMERROR(" not supported yet!");
    457 }
    458 /*}}}*/
    459 /*FUNCTION Penta::InputUpdateFromVectorDakota(double* vector, int name, int type);{{{1*/
    460 void  Penta::InputUpdateFromVectorDakota(double* vector, int name, int type){
    461         ISSMERROR(" not supported yet!");
    462 }
    463 /*}}}*/
    464 /*FUNCTION Penta::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{1*/
    465 void  Penta::InputUpdateFromVectorDakota(int* vector, int name, int type){
    466         ISSMERROR(" not supported yet!");
    467 }
    468 /*}}}*/
    469 /*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{1*/
    470 void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
    471         ISSMERROR(" not supported yet!");
    472 }
    473 /*}}}*/
    474 /*FUNCTION Penta::InputUpdateFromIoModel(int index,IoModel* iomodel) {{{1*/
    475 void Penta::InputUpdateFromIoModel(int index,IoModel* iomodel){
    476 
    477         /*Intermediaries*/
    478         IssmInt i,j;
    479         int     penta_vertex_ids[6];
    480         double  nodeinputs[6];
    481 
    482         /*Checks if debuging*/
    483         /*{{{2*/
    484         ISSMASSERT(iomodel->elements);
    485         /*}}}*/
    486 
    487         /*Recover vertices ids needed to initialize inputs*/
    488         for(i=0;i<6;i++){
    489                 penta_vertex_ids[i]=(int)iomodel->elements[6*index+i]; //ids for vertices are in the elements array from Matlab
    490         }
    491 
    492         //add as many inputs per element as requested:
    493         if (iomodel->thickness) {
    494                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->thickness[penta_vertex_ids[i]-1];
    495                 this->inputs->AddInput(new PentaVertexInput(ThicknessEnum,nodeinputs));
    496         }
    497         if (iomodel->surface) {
    498                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->surface[penta_vertex_ids[i]-1];
    499                 this->inputs->AddInput(new PentaVertexInput(SurfaceEnum,nodeinputs));
    500         }
    501         if (iomodel->bed) {
    502                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->bed[penta_vertex_ids[i]-1];
    503                 this->inputs->AddInput(new PentaVertexInput(BedEnum,nodeinputs));
    504         }
    505         if (iomodel->drag_coefficient) {
    506                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->drag_coefficient[penta_vertex_ids[i]-1];
    507                 this->inputs->AddInput(new PentaVertexInput(DragCoefficientEnum,nodeinputs));
    508 
    509                 if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
    510                 if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
    511                 this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
    512 
    513         }
    514         if (iomodel->melting_rate) {
    515                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->melting_rate[penta_vertex_ids[i]-1]/iomodel->yts;
    516                 this->inputs->AddInput(new PentaVertexInput(MeltingRateEnum,nodeinputs));
    517         }
    518         if (iomodel->accumulation_rate) {
    519                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->accumulation_rate[penta_vertex_ids[i]-1]/iomodel->yts;
    520                 this->inputs->AddInput(new PentaVertexInput(AccumulationRateEnum,nodeinputs));
    521         }
    522         if (iomodel->geothermalflux) {
    523                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->geothermalflux[penta_vertex_ids[i]-1];
    524                 this->inputs->AddInput(new PentaVertexInput(GeothermalFluxEnum,nodeinputs));
    525         }       
    526         if (iomodel->pressure) {
    527                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->pressure[penta_vertex_ids[i]-1];
    528                 this->inputs->AddInput(new PentaVertexInput(PressureEnum,nodeinputs));
    529         }
    530         if (iomodel->temperature) {
    531                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->temperature[penta_vertex_ids[i]-1];
    532                 this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,nodeinputs));
    533         }
    534         if (iomodel->dhdt) {
    535                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->dhdt[penta_vertex_ids[i]-1]/iomodel->yts;
    536                 this->inputs->AddInput(new PentaVertexInput(DhDtEnum,nodeinputs));
    537         }
    538         /*vx,vy and vz: */
    539         if (iomodel->vx) {
    540                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx[penta_vertex_ids[i]-1]/iomodel->yts;
    541                 this->inputs->AddInput(new PentaVertexInput(VxEnum,nodeinputs));
    542                 this->inputs->AddInput(new PentaVertexInput(VxOldEnum,nodeinputs));
    543                 if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVxEnum,nodeinputs));
    544         }
    545         if (iomodel->vy) {
    546                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy[penta_vertex_ids[i]-1]/iomodel->yts;
    547                 this->inputs->AddInput(new PentaVertexInput(VyEnum,nodeinputs));
    548                 this->inputs->AddInput(new PentaVertexInput(VyOldEnum,nodeinputs));
    549                 if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVyEnum,nodeinputs));
    550         }
    551         if (iomodel->vz) {
    552                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz[penta_vertex_ids[i]-1]/iomodel->yts;
    553                 this->inputs->AddInput(new PentaVertexInput(VzEnum,nodeinputs));
    554                 this->inputs->AddInput(new PentaVertexInput(VzOldEnum,nodeinputs));
    555                 if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVzEnum,nodeinputs));
    556         }
    557         if (iomodel->vx_obs) {
    558                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx_obs[penta_vertex_ids[i]-1]/iomodel->yts;
    559                 this->inputs->AddInput(new PentaVertexInput(VxObsEnum,nodeinputs));
    560         }
    561         if (iomodel->vy_obs) {
    562                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy_obs[penta_vertex_ids[i]-1]/iomodel->yts;
    563                 this->inputs->AddInput(new PentaVertexInput(VyObsEnum,nodeinputs));
    564         }
    565         if (iomodel->vz_obs) {
    566                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz_obs[penta_vertex_ids[i]-1]/iomodel->yts;
    567                 this->inputs->AddInput(new PentaVertexInput(VzObsEnum,nodeinputs));
    568         }
    569         if (iomodel->weights) {
    570                 for(i=0;i<6;i++)nodeinputs[i]=iomodel->weights[penta_vertex_ids[i]-1];
    571                 this->inputs->AddInput(new PentaVertexInput(WeightsEnum,nodeinputs));
    572         }
    573         if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
    574         if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
    575         if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
    576         if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
    577 
    578         /*time: */
    579         this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
    580 
    581         /*Control Inputs*/
    582         if (iomodel->control_analysis && iomodel->control_type){
    583                 for(i=0;i<iomodel->num_control_type;i++){
    584                         switch((int)iomodel->control_type[i]){
    585                                 case DhDtEnum:
    586                                         if (iomodel->dhdt){
    587                                                 for(j=0;j<6;j++)nodeinputs[j]=iomodel->dhdt[penta_vertex_ids[j]-1]/iomodel->yts;
    588                                                 this->inputs->AddInput(new ControlInput(DhDtEnum,PentaVertexInputEnum,nodeinputs,i+1));
    589                                         }
    590                                         break;
    591                                 case VxEnum:
    592                                         if (iomodel->vx){
    593                                                 for(j=0;j<6;j++)nodeinputs[j]=iomodel->vx[penta_vertex_ids[j]-1]/iomodel->yts;
    594                                                 this->inputs->AddInput(new ControlInput(VxEnum,PentaVertexInputEnum,nodeinputs,i+1));
    595                                         }
    596                                         break;
    597                                 case VyEnum:
    598                                         if (iomodel->vy){
    599                                                 for(j=0;j<6;j++)nodeinputs[j]=iomodel->vy[penta_vertex_ids[j]-1]/iomodel->yts;
    600                                                 this->inputs->AddInput(new ControlInput(VyEnum,PentaVertexInputEnum,nodeinputs,i+1));
    601                                         }
    602                                         break;
    603                                 case DragCoefficientEnum:
    604                                         if (iomodel->drag_coefficient){
    605                                                 for(j=0;j<6;j++)nodeinputs[j]=iomodel->drag_coefficient[penta_vertex_ids[j]-1];
    606                                                 this->inputs->AddInput(new ControlInput(DragCoefficientEnum,PentaVertexInputEnum,nodeinputs,i+1));
    607                                         }
    608                                         break;
    609                                 case RheologyBbarEnum:
    610                                         /*Matice will take care of it*/ break;
    611                                 default:
    612                                         ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
    613                         }
    614                 }
    615         }
    616 
    617         //Need to know the type of approximation for this element
    618         if(iomodel->elements_type){
    619                 if (*(iomodel->elements_type+index)==MacAyealApproximationEnum){
    620                         this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealApproximationEnum));
    621                 }
    622                 else if (*(iomodel->elements_type+index)==PattynApproximationEnum){
    623                         this->inputs->AddInput(new IntInput(ApproximationEnum,PattynApproximationEnum));
    624                 }
    625                 else if (*(iomodel->elements_type+index)==MacAyealPattynApproximationEnum){
    626                         this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealPattynApproximationEnum));
    627                 }
    628                 else if (*(iomodel->elements_type+index)==HutterApproximationEnum){
    629                         this->inputs->AddInput(new IntInput(ApproximationEnum,HutterApproximationEnum));
    630                 }
    631                 else if (*(iomodel->elements_type+index)==StokesApproximationEnum){
    632                         this->inputs->AddInput(new IntInput(ApproximationEnum,StokesApproximationEnum));
    633                 }
    634                 else if (*(iomodel->elements_type+index)==PattynStokesApproximationEnum){
    635                         this->inputs->AddInput(new IntInput(ApproximationEnum,PattynStokesApproximationEnum));
    636                 }
    637                 else if (*(iomodel->elements_type+index)==NoneApproximationEnum){
    638                         this->inputs->AddInput(new IntInput(ApproximationEnum,NoneApproximationEnum));
    639                 }
    640                 else{
    641                         ISSMERROR("Approximation type %s not supported yet",EnumToString((int)*(iomodel->elements_type+index)));
    642                 }
    643         }
    644 
    645 }
    646 /*}}}*/
    647 
    648 /*Element virtual functions definitions: */
     228/*FUNCTION Penta::Demarshall {{{1*/
     229void  Penta::Demarshall(char** pmarshalled_dataset){
     230
     231        char* marshalled_dataset=NULL;
     232        int   i;
     233        int flaghook;
     234
     235        /*recover marshalled_dataset: */
     236        marshalled_dataset=*pmarshalled_dataset;
     237
     238        /*this time, no need to get enum type, the pointer directly points to the beginning of the
     239         *object data (thanks to DataSet::Demarshall):*/
     240        memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
     241        memcpy(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
     242
     243        /*demarshall Ref: */
     244        this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
     245        for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
     246
     247        /*allocate dynamic memory: */
     248        this->hnodes=new Hook*[this->numanalyses];
     249        /*demarshall hooks: */
     250        for(i=0;i<numanalyses;i++){
     251                memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
     252                if(flaghook){ // there is a hook so demarshall it
     253                        hnodes[i]=new Hook();
     254                        hnodes[i]->Demarshall(&marshalled_dataset);
     255                }
     256                else hnodes[i]=NULL; //There is no hook so it is NULL
     257        }
     258        hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
     259        hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
     260        hneighbors=new Hook(); hneighbors->Demarshall(&marshalled_dataset);
     261
     262        /*pointers are garbage, until configuration is carried out: */
     263        nodes=NULL;
     264        matice=NULL;
     265        matpar=NULL;
     266        neighbors=NULL;
     267
     268        /*demarshall inputs and results: */
     269        inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset);
     270        results=(Results*)DataSetDemarshallRaw(&marshalled_dataset);
     271
     272        /*parameters: may not exist even yet, so let Configure handle it: */
     273        this->parameters=NULL;
     274
     275        /*return: */
     276        *pmarshalled_dataset=marshalled_dataset;
     277        return;
     278}
     279/*}}}*/
     280
     281/*Other*/
    649282/*FUNCTION Penta::AverageOntoPartition {{{1*/
    650283void  Penta::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
    651284        ISSMERROR("Not supported yet!");
     285}
     286/*}}}*/
     287/*FUNCTION Penta::BedNormal {{{1*/
     288void Penta::BedNormal(double* bed_normal, double xyz_list[3][3]){
     289
     290        int i;
     291        double v13[3],v23[3];
     292        double normal[3];
     293        double normal_norm;
     294
     295        for (i=0;i<3;i++){
     296                v13[i]=xyz_list[0][i]-xyz_list[2][i];
     297                v23[i]=xyz_list[1][i]-xyz_list[2][i];
     298        }
     299
     300        normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
     301        normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
     302        normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
     303        normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
     304
     305        /*Bed normal is opposite to surface normal*/
     306        *(bed_normal)=-normal[0]/normal_norm;
     307        *(bed_normal+1)=-normal[1]/normal_norm;
     308        *(bed_normal+2)=-normal[2]/normal_norm;
    652309}
    653310/*}}}*/
     
    837494
    838495}/*}}}*/
    839 /*FUNCTION Penta::RegularizeInversion {{{1*/
    840 double Penta::RegularizeInversion(void){
    841 
    842         double J;
    843         Tria* tria=NULL;
    844 
    845         /*recover some inputs: */
    846         int  approximation;
    847         inputs->GetParameterValue(&approximation,ApproximationEnum);
    848 
    849         /*If on water, return 0: */
    850         if(IsOnWater())return 0;
    851 
    852         /*Bail out if this element if:
    853          * -> Not MacAyeal and not on the surface
    854          * -> MacAyeal (2d model) and not on bed) */
    855         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    856                 return 0;
    857         }
    858         else if (approximation==MacAyealApproximationEnum){
    859 
    860                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    861                  * and compute RegularizeInversion*/
    862 
    863                 /*Depth Average B*/
    864                 this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
    865 
    866                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    867                 J=tria->RegularizeInversion();
    868                 delete tria->matice; delete tria;
    869 
    870                 /*delete B average*/
    871                 this->matice->inputs->DeleteInput(RheologyBbarEnum);
    872 
    873                 return J;
    874         }
    875         else{
    876 
    877                 /*Depth Average B and put it in inputs*/
    878                 Penta* penta=GetBasalElement();
    879                 penta->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
    880                 Input* B_input=penta->matice->inputs->GetInput(RheologyBbarEnum);
    881                 Input* B_copy=(Input*)B_input->copy();
    882                 this->matice->inputs->AddInput((Input*)B_copy);
    883 
    884                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    885                 J=tria->RegularizeInversion();
    886                 delete tria->matice; delete tria;
    887 
    888                 /*delete B average*/
    889                 this->matice->inputs->DeleteInput(RheologyBbarEnum);
    890                 penta->matice->inputs->DeleteInput(RheologyBbarEnum);
    891 
    892                 return J;
    893         }
    894 }
    895 /*}}}*/
    896496/*FUNCTION Penta::CreateKMatrix {{{1*/
    897497void  Penta::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
     
    944544                delete Ke;
    945545        }
     546}
     547/*}}}*/
     548/*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
     549ElementMatrix* Penta::CreateKMatrixBalancedthickness(void){
     550
     551        /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
     552          bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
     553          the stiffness matrix. */
     554        if (!IsOnBed() || IsOnWater()) return NULL;
     555
     556        /*Depth Averaging Vx and Vy*/
     557        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     558        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     559
     560        /*Spawn Tria element from the base of the Penta: */
     561        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     562        ElementMatrix* Ke=tria->CreateKMatrixBalancedthickness();
     563        delete tria->matice; delete tria;
     564
     565        /*Delete Vx and Vy averaged*/
     566        this->inputs->DeleteInput(VxAverageEnum);
     567        this->inputs->DeleteInput(VyAverageEnum);
     568
     569        /*clean up and return*/
     570        return Ke;
     571}
     572/*}}}*/
     573/*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
     574ElementMatrix* Penta::CreateKMatrixBalancedvelocities(void){
     575
     576        /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
     577          bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
     578          the stiffness matrix. */
     579        if (!IsOnBed() || IsOnWater()) return NULL;
     580
     581        /*Depth Averaging Vx and Vy*/
     582        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     583        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     584
     585        /*Spawn Tria element from the base of the Penta: */
     586        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     587        ElementMatrix* Ke=tria->CreateKMatrixBalancedvelocities();
     588        delete tria->matice; delete tria;
     589
     590        /*Delete Vx and Vy averaged*/
     591        this->inputs->DeleteInput(VxAverageEnum);
     592        this->inputs->DeleteInput(VyAverageEnum);
     593
     594        /*clean up and return*/
     595        return Ke;
     596}
     597/*}}}*/
     598/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattyn{{{1*/
     599ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattyn(void){
     600
     601        /*compute all stiffness matrices for this element*/
     602        ElementMatrix* Ke1=CreateKMatrixCouplingMacAyealPattynViscous();
     603        ElementMatrix* Ke2=CreateKMatrixCouplingMacAyealPattynFriction();
     604        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     605
     606        /*clean-up and return*/
     607        delete Ke1;
     608        delete Ke2;
     609        return Ke;
     610}
     611/*}}}*/
     612/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynViscous{{{1*/
     613ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynViscous(void){
     614
     615        /*Constants*/
     616        const int    numdofm=NDOF2*NUMVERTICES2D;
     617        const int    numdofp=NDOF2*NUMVERTICES;
     618        const int    numdoftotal=2*NDOF2*NUMVERTICES;
     619
     620        /*Intermediaries */
     621        int         i,j,ig;
     622        double      Jdet;
     623        double      viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
     624        double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
     625        double      xyz_list[NUMVERTICES][3];
     626        double      B[3][numdofp];
     627        double      Bprime[3][numdofm];
     628        double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
     629        double      D_scalar;
     630        double      Ke_gg[numdofp][numdofm]={0.0}; //local element stiffness matrix
     631        double      Ke_gg_gaussian[numdofp][numdofm]; //stiffness matrix evaluated at the gaussian point.
     632        GaussPenta *gauss=NULL;
     633        GaussTria  *gauss_tria=NULL;
     634
     635        /*Find penta on bed as pattyn must be coupled to the dofs on the bed: */
     636        Penta* pentabase=GetBasalElement();
     637        Tria* tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     638
     639        /*Initialize Element matrix and return if necessary*/
     640        if(IsOnWater()) return NULL;
     641        ElementMatrix* Ke1=new ElementMatrix(pentabase->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
     642        ElementMatrix* Ke2=new ElementMatrix(this->nodes     ,NUMVERTICES,this->parameters,PattynApproximationEnum);
     643        ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
     644        delete Ke1; delete Ke2;
     645
     646        /* Get node coordinates and dof list: */
     647        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     648        this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
     649        Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
     650        Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
     651        Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
     652        Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
     653
     654        /* Start  looping on the number of gaussian points: */
     655        gauss=new GaussPenta(5,5);
     656        gauss_tria=new GaussTria();
     657        for (ig=gauss->begin();ig<gauss->end();ig++){
     658
     659                gauss->GaussPoint(ig);
     660                gauss->SynchronizeGaussTria(gauss_tria);
     661
     662                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     663                GetBMacAyealPattyn(&B[0][0], &xyz_list[0][0], gauss);
     664                tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
     665
     666                this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
     667                this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
     668                matice->GetViscosity3d(&viscosity, &epsilon[0]);
     669                matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
     670
     671                newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
     672                D_scalar=2*newviscosity*gauss->weight*Jdet;
     673                for (i=0;i<3;i++) D[i][i]=D_scalar;
     674
     675                TripleMultiply( &B[0][0],3,numdofp,1,
     676                                        &D[0][0],3,3,0,
     677                                        &Bprime[0][0],3,numdofm,0,
     678                                        &Ke_gg_gaussian[0][0],0);
     679
     680                for( i=0; i<numdofp; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
     681        }
     682        for(i=0;i<numdofp;i++) for(j=0;j<numdofm;j++) Ke->values[(i+2*numdofm)*numdoftotal+j]+=Ke_gg[i][j];
     683        for(i=0;i<numdofm;i++) for(j=0;j<numdofp;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg[j][i];
     684
     685        /*Clean-up and return*/
     686        delete tria->matice; delete tria;
     687        delete gauss;
     688        delete gauss_tria;
     689        return Ke;
     690}
     691/*}}}*/
     692/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynFriction{{{1*/
     693ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynFriction(void){
     694
     695        /*Initialize Element matrix and return if necessary*/
     696        if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
     697
     698        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     699        ElementMatrix* Ke=tria->CreateKMatrixCouplingMacAyealPattynFriction();
     700        delete tria->matice; delete tria;
     701
     702        return Ke;
     703}
     704/*}}}*/
     705/*FUNCTION Penta::CreateKMatrixCouplingPattynStokes{{{1*/
     706ElementMatrix* Penta::CreateKMatrixCouplingPattynStokes(void){
     707
     708        /*compute all stiffness matrices for this element*/
     709        ElementMatrix* Ke1=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
     710        ElementMatrix* Ke2=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     711        ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
     712        delete Ke1;
     713        delete Ke2;
     714        Ke1=CreateKMatrixDiagnosticPattyn();
     715        Ke2=CreateKMatrixDiagnosticStokes();
     716
     717        /*Constants*/
     718        const int    numdofp=NDOF2*NUMVERTICES;
     719        const int    numdofs=NDOF4*NUMVERTICES;
     720        const int    numdoftotal=(NDOF2+NDOF4)*NUMVERTICES;
     721        int          i,j;
     722
     723        for(i=0;i<numdofs;i++) for(j=0;j<NUMVERTICES;j++){
     724                Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+0]+=Ke2->values[i*numdofs+NDOF4*j+0];
     725                Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+1]+=Ke2->values[i*numdofs+NDOF4*j+1];
     726        }
     727        for(i=0;i<numdofp;i++) for(j=0;j<NUMVERTICES;j++){
     728                Ke->values[i*numdoftotal+numdofp+NDOF4*j+0]+=Ke1->values[i*numdofp+NDOF2*j+0];
     729                Ke->values[i*numdoftotal+numdofp+NDOF4*j+1]+=Ke1->values[i*numdofp+NDOF2*j+1];
     730        }
     731
     732        /*clean-up and return*/
     733        delete Ke1;
     734        delete Ke2;
     735        return Ke;
     736}
     737/*}}}*/
     738/*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
     739ElementMatrix* Penta::CreateKMatrixDiagnosticHoriz(void){
     740
     741        int approximation;
     742        inputs->GetParameterValue(&approximation,ApproximationEnum);
     743
     744        switch(approximation){
     745                case MacAyealApproximationEnum:
     746                        return CreateKMatrixDiagnosticMacAyeal2d();
     747                case PattynApproximationEnum:
     748                        return CreateKMatrixDiagnosticPattyn();
     749                case StokesApproximationEnum:
     750                        return CreateKMatrixDiagnosticStokes();
     751                case HutterApproximationEnum:
     752                        return NULL;
     753                case NoneApproximationEnum:
     754                        return NULL;
     755                case MacAyealPattynApproximationEnum:
     756                        return CreateKMatrixDiagnosticMacAyealPattyn();
     757                case PattynStokesApproximationEnum:
     758                        return CreateKMatrixDiagnosticPattynStokes();
     759                default:
     760                        ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
     761        }
     762}
     763/*}}}*/
     764/*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
     765ElementMatrix* Penta::CreateKMatrixDiagnosticHutter(void){
     766
     767        /*Constants*/
     768        const int numdof=NDOF2*NUMVERTICES;
     769
     770        /*Intermediaries*/
     771        int       connectivity[2];
     772        int       i,i0,i1,j0,j1;
     773        double    one0,one1;
     774
     775        /*Initialize Element matrix and return if necessary*/
     776        if(IsOnWater()) return NULL;
     777        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     778
     779        /*Spawn 3 beam elements: */
     780        for(i=0;i<3;i++){
     781                /*2 dofs of first node*/
     782                i0=2*i;
     783                i1=2*i+1;
     784                /*2 dofs of second node*/
     785                j0=2*(i+3);
     786                j1=2*(i+3)+1;
     787
     788                /*Find connectivity for the two nodes*/
     789                connectivity[0]=nodes[i]->GetConnectivity();
     790                connectivity[1]=nodes[i+3]->GetConnectivity();
     791                one0=1/(double)connectivity[0];
     792                one1=1/(double)connectivity[1];
     793
     794                /*Create matrix for these two nodes*/
     795                if (IsOnBed() && IsOnSurface()){
     796                        Ke->values[i0*numdof+i0]=one0;
     797                        Ke->values[i1*numdof+i1]=one0;
     798                        Ke->values[j0*numdof+i0]=-one1;
     799                        Ke->values[j0*numdof+j0]=one1;
     800                        Ke->values[j1*numdof+i1]=-one1;
     801                        Ke->values[j1*numdof+j1]=one1;
     802                }
     803                else if (IsOnBed()){
     804                        Ke->values[i0*numdof+i0]=one0;
     805                        Ke->values[i1*numdof+i1]=one0;
     806                        Ke->values[j0*numdof+i0]=-2*one1;
     807                        Ke->values[j0*numdof+j0]=2*one1;
     808                        Ke->values[j1*numdof+i1]=-2*one1;
     809                        Ke->values[j1*numdof+j1]=2*one1;
     810                }
     811                else if (IsOnSurface()){
     812                        Ke->values[j0*numdof+i0]=-one1;
     813                        Ke->values[j0*numdof+j0]=one1;
     814                        Ke->values[j1*numdof+i1]=-one1;
     815                        Ke->values[j1*numdof+j1]=one1;
     816                }
     817                else{ //node is on two horizontal layers and beams include the values only once, so the have to use half of the connectivity
     818                        Ke->values[j0*numdof+i0]=-2*one1;
     819                        Ke->values[j0*numdof+j0]=2*one1;
     820                        Ke->values[j1*numdof+i1]=-2*one1;
     821                        Ke->values[j1*numdof+j1]=2*one1;
     822                }
     823        }
     824
     825        /*Clean up and return*/
     826        return Ke;
     827}
     828/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal2d{{{1*/
     829ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal2d(void){
     830
     831        /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
     832          bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
     833          the stiffness matrix. */
     834        if (!IsOnBed() || IsOnWater()) return NULL;
     835
     836        /*Depth Averaging B*/
     837        this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
     838
     839        /*Call Tria function*/
     840        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     841        ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyeal();
     842        delete tria->matice; delete tria;
     843
     844        /*Delete B averaged*/
     845        this->matice->inputs->DeleteInput(RheologyBbarEnum);
     846
     847        /*clean up and return*/
     848        return Ke;
     849}
     850/*}}}*/
     851/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3d{{{1*/
     852ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3d(void){
     853
     854        /*compute all stiffness matrices for this element*/
     855        ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3dViscous();
     856        ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyeal3dFriction();
     857        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     858
     859        /*clean-up and return*/
     860        delete Ke1;
     861        delete Ke2;
     862        return Ke;
     863}
     864/*}}}*/
     865/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dViscous{{{1*/
     866ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dViscous(void){
     867
     868        /*Constants*/
     869        const int    numdof2d=2*NUMVERTICES2D;
     870
     871        /*Intermediaries */
     872        int         i,j,ig;
     873        double      Jdet;
     874        double      viscosity, oldviscosity, newviscosity, viscosity_overshoot;
     875        double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
     876        double      xyz_list[NUMVERTICES][3];
     877        double      B[3][numdof2d];
     878        double      Bprime[3][numdof2d];
     879        double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
     880        double      D_scalar;
     881        double      Ke_gg_gaussian[numdof2d][numdof2d]; //stiffness matrix evaluated at the gaussian point.
     882        Tria*       tria=NULL;
     883        Penta*      pentabase=NULL;
     884        GaussPenta *gauss=NULL;
     885        GaussTria  *gauss_tria=NULL;
     886
     887        /*Find penta on bed as this is a macayeal elements: */
     888        pentabase=GetBasalElement();
     889        tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     890
     891        /*Initialize Element matrix and return if necessary*/
     892        if(IsOnWater()) return NULL;
     893        ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,MacAyealApproximationEnum);
     894
     895        /*Retrieve all inputs and parameters*/
     896        GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES);
     897        this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
     898        Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
     899        Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
     900        Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
     901        Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
     902
     903        /* Start  looping on the number of gaussian points: */
     904        gauss=new GaussPenta(5,5);
     905        gauss_tria=new GaussTria();
     906        for (ig=gauss->begin();ig<gauss->end();ig++){
     907
     908                gauss->GaussPoint(ig);
     909                gauss->SynchronizeGaussTria(gauss_tria);
     910
     911                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     912                tria->GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss_tria);
     913                tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
     914
     915                this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
     916                this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
     917                matice->GetViscosity3d(&viscosity, &epsilon[0]);
     918                matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
     919
     920                newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
     921                D_scalar=2*newviscosity*gauss->weight*Jdet;
     922                for (i=0;i<3;i++) D[i][i]=D_scalar;
     923
     924                TripleMultiply( &B[0][0],3,numdof2d,1,
     925                                        &D[0][0],3,3,0,
     926                                        &Bprime[0][0],3,numdof2d,0,
     927                                        &Ke_gg_gaussian[0][0],0);
     928
     929                for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof2d+j]+=Ke_gg_gaussian[i][j];
     930        }
     931
     932        /*Clean up and return*/
     933        delete tria->matice;
     934        delete tria;
     935        delete gauss_tria;
     936        delete gauss;
     937        return Ke;
     938}
     939/*}}}*/
     940/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dFriction{{{1*/
     941ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dFriction(void){
     942
     943        /*Initialize Element matrix and return if necessary*/
     944        if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
     945
     946        /*Build a tria element using the 3 grids of the base of the penta. Then use
     947         * the tria functionality to build a friction stiffness matrix on these 3
     948         * grids: */
     949        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     950        ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
     951        delete tria->matice; delete tria;
     952
     953        /*clean-up and return*/
     954        return Ke;
     955}
     956/*}}}*/
     957/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyealPattyn{{{1*/
     958ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyealPattyn(void){
     959
     960        /*compute all stiffness matrices for this element*/
     961        ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3d();
     962        ElementMatrix* Ke2=CreateKMatrixDiagnosticPattyn();
     963        ElementMatrix* Ke3=CreateKMatrixCouplingMacAyealPattyn();
     964        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
     965
     966        /*clean-up and return*/
     967        delete Ke1;
     968        delete Ke2;
     969        delete Ke3;
     970        return Ke;
     971}
     972/*}}}*/
     973/*FUNCTION Penta::CreateKMatrixDiagnosticPattyn{{{1*/
     974ElementMatrix* Penta::CreateKMatrixDiagnosticPattyn(void){
     975
     976        /*compute all stiffness matrices for this element*/
     977        ElementMatrix* Ke1=CreateKMatrixDiagnosticPattynViscous();
     978        ElementMatrix* Ke2=CreateKMatrixDiagnosticPattynFriction();
     979        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     980
     981        /*clean-up and return*/
     982        delete Ke1;
     983        delete Ke2;
     984        return Ke;
     985}
     986/*}}}*/
     987/*FUNCTION Penta::CreateKMatrixDiagnosticPattynViscous{{{1*/
     988ElementMatrix* Penta::CreateKMatrixDiagnosticPattynViscous(void){
     989
     990        /*Constants*/
     991        const int    numdof=NDOF2*NUMVERTICES;
     992
     993        /*Intermediaries */
     994        int        i,j,ig;
     995        int        approximation;
     996        double     xyz_list[NUMVERTICES][3];
     997        double     Jdet;
     998        double     viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
     999        double     epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
     1000        double     D_scalar;
     1001        double     D[5][5]={0.0};            // material matrix, simple scalar matrix.
     1002        double     B[5][numdof];
     1003        double     Bprime[5][numdof];
     1004        double     Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
     1005        Tria*      tria=NULL;
     1006        GaussPenta *gauss=NULL;
     1007
     1008        /*Initialize Element matrix and return if necessary*/
     1009        if(IsOnWater()) return NULL;
     1010        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
     1011
     1012        /*Retrieve all inputs and parameters*/
     1013        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1014        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1015        this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
     1016        Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
     1017        Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
     1018        Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
     1019        Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
     1020
     1021        /* Start  looping on the number of gaussian points: */
     1022        gauss=new GaussPenta(5,5);
     1023        for (ig=gauss->begin();ig<gauss->end();ig++){
     1024
     1025                gauss->GaussPoint(ig);
     1026
     1027                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     1028                GetBPattyn(&B[0][0], &xyz_list[0][0], gauss);
     1029                GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss);
     1030
     1031                this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
     1032                this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
     1033                matice->GetViscosity3d(&viscosity, &epsilon[0]);
     1034                matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
     1035                newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
     1036
     1037                D_scalar=2*newviscosity*gauss->weight*Jdet;
     1038                for (i=0;i<5;i++) D[i][i]=D_scalar;
     1039
     1040                TripleMultiply( &B[0][0],5,numdof,1,
     1041                                        &D[0][0],5,5,0,
     1042                                        &Bprime[0][0],5,numdof,0,
     1043                                        &Ke_gg_gaussian[0][0],0);
     1044
     1045                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     1046        }
     1047
     1048        /*Clean up and return*/
     1049        delete gauss;
     1050        return Ke;
     1051}
     1052/*}}}*/
     1053/*FUNCTION Penta::CreateKMatrixDiagnosticPattynFriction{{{1*/
     1054ElementMatrix* Penta::CreateKMatrixDiagnosticPattynFriction(void){
     1055
     1056        /*Initialize Element matrix and return if necessary*/
     1057        if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
     1058
     1059        /*Build a tria element using the 3 grids of the base of the penta. Then use
     1060         * the tria functionality to build a friction stiffness matrix on these 3
     1061         * grids: */
     1062        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1063        ElementMatrix* Ke=tria->CreateKMatrixDiagnosticPattynFriction();
     1064        delete tria->matice; delete tria;
     1065
     1066        /*clean-up and return*/
     1067        return Ke;
     1068}
     1069/*}}}*/
     1070/*FUNCTION Penta::CreateKMatrixDiagnosticPattynStokes{{{1*/
     1071ElementMatrix* Penta::CreateKMatrixDiagnosticPattynStokes(void){
     1072
     1073        /*compute all stiffness matrices for this element*/
     1074        ElementMatrix* Ke1=CreateKMatrixDiagnosticPattyn();
     1075        ElementMatrix* Ke2=CreateKMatrixDiagnosticStokes();
     1076        ElementMatrix* Ke3=CreateKMatrixCouplingPattynStokes();
     1077        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
     1078
     1079        /*clean-up and return*/
     1080        delete Ke1;
     1081        delete Ke2;
     1082        delete Ke3;
     1083        return Ke;
     1084}
     1085/*}}}*/
     1086/*FUNCTION Penta::CreateKMatrixDiagnosticStokes{{{1*/
     1087ElementMatrix* Penta::CreateKMatrixDiagnosticStokes(void){
     1088
     1089        /*compute all stiffness matrices for this element*/
     1090        ElementMatrix* Ke1=CreateKMatrixDiagnosticStokesViscous();
     1091        ElementMatrix* Ke2=CreateKMatrixDiagnosticStokesFriction();
     1092        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     1093
     1094        /*clean-up and return*/
     1095        delete Ke1;
     1096        delete Ke2;
     1097        return Ke;
     1098}
     1099/*}}}*/
     1100/*FUNCTION Penta::CreateKMatrixDiagnosticStokesViscous {{{1*/
     1101ElementMatrix* Penta::CreateKMatrixDiagnosticStokesViscous(void){
     1102
     1103        /*Intermediaries */
     1104        int        i,j,ig,approximation;
     1105        double     Jdet,viscosity,stokesreconditioning;
     1106        double     xyz_list[NUMVERTICES][3];
     1107        double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     1108        double     B[8][27];
     1109        double     B_prime[8][27];
     1110        double     D_scalar;
     1111        double     D[8][8]={0.0};
     1112        double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble
     1113        double     Ke_gaussian[27][27];
     1114        GaussPenta *gauss=NULL;
     1115
     1116        /*If on water or not Stokes, skip stiffness: */
     1117        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1118        if(IsOnWater() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
     1119        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     1120
     1121        /*Retrieve all inputs and parameters*/
     1122        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1123        parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     1124        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     1125        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     1126        Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
     1127
     1128        /* Start  looping on the number of gaussian points: */
     1129        gauss=new GaussPenta(5,5);
     1130        for (ig=gauss->begin();ig<gauss->end();ig++){
     1131
     1132                gauss->GaussPoint(ig);
     1133
     1134                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     1135                GetBStokes(&B[0][0],&xyz_list[0][0],gauss);
     1136                GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0],gauss);
     1137
     1138                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     1139                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     1140
     1141                D_scalar=gauss->weight*Jdet;
     1142                for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
     1143                for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
     1144
     1145                TripleMultiply( &B[0][0],8,27,1,
     1146                                        &D[0][0],8,8,0,
     1147                                        &B_prime[0][0],8,27,0,
     1148                                        &Ke_gaussian[0][0],0);
     1149
     1150                for(i=0;i<27;i++) for(j=0;j<27;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
     1151        }
     1152
     1153        /*Condensation*/
     1154        ReduceMatrixStokes(Ke->values, &Ke_temp[0][0]);
     1155
     1156        /*Clean up and return*/
     1157        delete gauss;
     1158        return Ke;
     1159}
     1160/*}}}*/
     1161/*FUNCTION Penta::CreateKMatrixDiagnosticStokesFriction {{{1*/
     1162ElementMatrix* Penta::CreateKMatrixDiagnosticStokesFriction(void){
     1163
     1164        /*Constants*/
     1165        const int numdof=NUMVERTICES*NDOF4;
     1166        const int numdof2d=NUMVERTICES2D*NDOF4;
     1167
     1168        /*Intermediaries */
     1169        int        i,j,ig;
     1170        int        analysis_type,approximation;
     1171        double     stokesreconditioning;
     1172        double     viscosity,alpha2_gauss,Jdet2d;
     1173        double    bed_normal[3];
     1174        double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     1175        double     xyz_list[NUMVERTICES][3];
     1176        double    xyz_list_tria[NUMVERTICES2D][3];
     1177        double     LStokes[14][numdof2d];
     1178        double     LprimeStokes[14][numdof2d];
     1179        double     DLStokes[14][14]={0.0};
     1180        double     Ke_drag_gaussian[numdof2d][numdof2d];
     1181        Friction*  friction=NULL;
     1182        GaussPenta *gauss=NULL;
     1183
     1184        /*If on water or not Stokes, skip stiffness: */
     1185        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1186        if(IsOnWater() || IsOnShelf() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
     1187        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     1188
     1189        /*Retrieve all inputs and parameters*/
     1190        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1191        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     1192        parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     1193        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     1194        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     1195        Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
     1196        for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
     1197
     1198        /*build friction object, used later on: */
     1199        friction=new Friction("3d",inputs,matpar,analysis_type);
     1200
     1201        /* Start  looping on the number of gaussian points: */
     1202        gauss=new GaussPenta(0,1,2,2);
     1203        for (ig=gauss->begin();ig<gauss->end();ig++){
     1204
     1205                gauss->GaussPoint(ig);
     1206
     1207                GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
     1208                GetLStokes(&LStokes[0][0], gauss);
     1209                GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss);
     1210
     1211                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     1212                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     1213
     1214                BedNormal(&bed_normal[0],xyz_list_tria);
     1215                friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
     1216
     1217                DLStokes[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
     1218                DLStokes[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
     1219                DLStokes[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
     1220                DLStokes[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
     1221                DLStokes[4][4]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
     1222                DLStokes[5][5]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
     1223                DLStokes[6][6]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0];
     1224                DLStokes[7][7]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1];
     1225                DLStokes[8][8]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[2];
     1226                DLStokes[9][9]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0]/2.0;
     1227                DLStokes[10][10]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1]/2.0;
     1228                DLStokes[11][11]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[0];
     1229                DLStokes[12][12]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[1];
     1230                DLStokes[13][13]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[2];
     1231
     1232                TripleMultiply( &LStokes[0][0],14,numdof2d,1,
     1233                                        &DLStokes[0][0],14,14,0,
     1234                                        &LprimeStokes[0][0],14,numdof2d,0,
     1235                                        &Ke_drag_gaussian[0][0],0);
     1236
     1237                for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof+j]+=Ke_drag_gaussian[i][j];
     1238        }
     1239
     1240        /*Clean up and return*/
     1241        delete gauss;
     1242        delete friction;
     1243        return Ke;
     1244}
     1245/*}}}*/
     1246/*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
     1247ElementMatrix* Penta::CreateKMatrixDiagnosticVert(void){
     1248
     1249        /*compute all stiffness matrices for this element*/
     1250        ElementMatrix* Ke1=CreateKMatrixDiagnosticVertVolume();
     1251        ElementMatrix* Ke2=CreateKMatrixDiagnosticVertSurface();
     1252        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     1253
     1254        /*clean-up and return*/
     1255        delete Ke1;
     1256        delete Ke2;
     1257        return Ke;
     1258}
     1259/*}}}*/
     1260/*FUNCTION Penta::CreateKMatrixDiagnosticVertVolume {{{1*/
     1261ElementMatrix* Penta::CreateKMatrixDiagnosticVertVolume(void){
     1262
     1263        /*Constants*/
     1264        const int    numdof=NDOF1*NUMVERTICES;
     1265
     1266        /*Intermediaries */
     1267        int         i,j,ig;
     1268        double      Jdet;
     1269        double      xyz_list[NUMVERTICES][3];
     1270        double      B[NDOF1][NUMVERTICES];
     1271        double      Bprime[NDOF1][NUMVERTICES];
     1272        double      DL_scalar;
     1273        double      Ke_gg[numdof][numdof]={0.0};
     1274        GaussPenta  *gauss=NULL;
     1275
     1276        /*Initialize Element matrix and return if necessary*/
     1277        if(IsOnWater()) return NULL;
     1278        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1279
     1280        /*Retrieve all inputs and parameters*/
     1281        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1282
     1283        /* Start  looping on the number of gaussian points: */
     1284        gauss=new GaussPenta(2,2);
     1285        for (ig=gauss->begin();ig<gauss->end();ig++){
     1286
     1287                gauss->GaussPoint(ig);
     1288
     1289                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     1290                GetBVert(&B[0][0], &xyz_list[0][0], gauss);
     1291                GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss);
     1292
     1293                DL_scalar=gauss->weight*Jdet;
     1294
     1295                TripleMultiply( &B[0][0],1,NUMVERTICES,1,
     1296                                        &DL_scalar,1,1,0,
     1297                                        &Bprime[0][0],1,NUMVERTICES,0,
     1298                                        &Ke_gg[0][0],0);
     1299
     1300                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
     1301        }
     1302
     1303        /*Clean up and return*/
     1304        delete gauss;
     1305        return Ke;
     1306}
     1307/*}}}*/
     1308/*FUNCTION Penta::CreateKMatrixDiagnosticVertSurface {{{1*/
     1309ElementMatrix* Penta::CreateKMatrixDiagnosticVertSurface(void){
     1310
     1311        if (!IsOnSurface() || IsOnWater()) return NULL;
     1312
     1313        /*Call Tria function*/
     1314        Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
     1315        ElementMatrix* Ke=tria->CreateKMatrixDiagnosticVertSurface();
     1316        delete tria->matice; delete tria;
     1317
     1318        /*clean up and return*/
     1319        return Ke;
     1320}
     1321/*}}}*/
     1322/*FUNCTION Penta::CreateKMatrixMelting {{{1*/
     1323ElementMatrix* Penta::CreateKMatrixMelting(void){
     1324
     1325        if (!IsOnBed() || IsOnWater()) return NULL;
     1326
     1327        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1328        ElementMatrix* Ke=tria->CreateKMatrixMelting();
     1329
     1330        delete tria->matice; delete tria;
     1331        return Ke;
     1332}
     1333/*}}}*/
     1334/*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
     1335ElementMatrix* Penta::CreateKMatrixPrognostic(void){
     1336
     1337        if (!IsOnBed() || IsOnWater()) return NULL;
     1338
     1339        /*Depth Averaging Vx and Vy*/
     1340        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     1341        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     1342
     1343        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1344        ElementMatrix* Ke=tria->CreateKMatrixPrognostic();
     1345        delete tria->matice; delete tria;
     1346
     1347        /*Delete Vx and Vy averaged*/
     1348        this->inputs->DeleteInput(VxAverageEnum);
     1349        this->inputs->DeleteInput(VyAverageEnum);
     1350
     1351        /*clean up and return*/
     1352        return Ke;
     1353}
     1354/*}}}*/
     1355/*FUNCTION Penta::CreateKMatrixSlope {{{1*/
     1356ElementMatrix* Penta::CreateKMatrixSlope(void){
     1357
     1358        if (!IsOnBed() || IsOnWater()) return NULL;
     1359
     1360        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1361        ElementMatrix* Ke=tria->CreateKMatrixSlope();
     1362        delete tria->matice; delete tria;
     1363
     1364        /*clean up and return*/
     1365        return Ke;
     1366}
     1367/*}}}*/
     1368/*FUNCTION Penta::CreateKMatrixThermal {{{1*/
     1369ElementMatrix* Penta::CreateKMatrixThermal(void){
     1370
     1371        /*compute all stiffness matrices for this element*/
     1372        ElementMatrix* Ke1=CreateKMatrixThermalVolume();
     1373        ElementMatrix* Ke2=CreateKMatrixThermalShelf();
     1374        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     1375
     1376        /*clean-up and return*/
     1377        delete Ke1;
     1378        delete Ke2;
     1379        return Ke;
     1380}
     1381/*}}}*/
     1382/*FUNCTION Penta::CreateKMatrixThermalVolume {{{1*/
     1383ElementMatrix* Penta::CreateKMatrixThermalVolume(void){
     1384
     1385        /*Constants*/
     1386        const int    numdof=NDOF1*NUMVERTICES;
     1387
     1388        /*Intermediaries */
     1389        int        artdiff;
     1390        int        i,j,ig,found=0;
     1391        double     Jdet,u,v,w,epsvel;
     1392        double     gravity,rho_ice,rho_water;
     1393        double     heatcapacity,thermalconductivity,dt;
     1394        double     tau_parameter,diameter;
     1395        double     xyz_list[NUMVERTICES][3];
     1396        double     B[3][numdof];
     1397        double     Bprime[3][numdof];
     1398        double     B_conduct[3][numdof];
     1399        double     B_advec[3][numdof];
     1400        double     B_artdiff[2][numdof];
     1401        double     Bprime_advec[3][numdof];
     1402        double     L[numdof];
     1403        double     dh1dh6[3][6];
     1404        double     D_scalar_conduct,D_scalar_advec;
     1405        double     D_scalar_trans,D_scalar_artdiff;
     1406        double     D[3][3];
     1407        double     K[2][2]={0.0};
     1408        double     Ke_gaussian_conduct[numdof][numdof];
     1409        double     Ke_gaussian_advec[numdof][numdof];
     1410        double     Ke_gaussian_artdiff[numdof][numdof];
     1411        double     Ke_gaussian_transient[numdof][numdof];
     1412        Tria*      tria=NULL;
     1413        GaussPenta *gauss=NULL;
     1414
     1415        /*Initialize Element matrix and return if necessary*/
     1416        if(IsOnWater()) return NULL;
     1417        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1418
     1419        /*Retrieve all inputs and parameters*/
     1420        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1421        rho_water=matpar->GetRhoWater();
     1422        rho_ice=matpar->GetRhoIce();
     1423        gravity=matpar->GetG();
     1424        heatcapacity=matpar->GetHeatCapacity();
     1425        thermalconductivity=matpar->GetThermalConductivity();
     1426        this->inputs->GetParameterValue(&dt,DtEnum);
     1427        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     1428        this->parameters->FindParam(&epsvel,EpsVelEnum);
     1429        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     1430        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     1431        Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
     1432        if (artdiff==2) diameter=MinEdgeLength(xyz_list);
     1433
     1434        /* Start  looping on the number of gaussian points: */
     1435        gauss=new GaussPenta(2,2);
     1436        for (ig=gauss->begin();ig<gauss->end();ig++){
     1437
     1438                gauss->GaussPoint(ig);
     1439
     1440                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     1441
     1442                /*Conduction: */
     1443
     1444                GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss);
     1445
     1446                D_scalar_conduct=gauss->weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
     1447                if(dt) D_scalar_conduct=D_scalar_conduct*dt;
     1448
     1449                D[0][0]=D_scalar_conduct; D[0][1]=0; D[0][2]=0;
     1450                D[1][0]=0; D[1][1]=D_scalar_conduct; D[1][2]=0;
     1451                D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar_conduct;
     1452
     1453                TripleMultiply(&B_conduct[0][0],3,numdof,1,
     1454                                        &D[0][0],3,3,0,
     1455                                        &B_conduct[0][0],3,numdof,0,
     1456                                        &Ke_gaussian_conduct[0][0],0);
     1457
     1458                /*Advection: */
     1459
     1460                GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss);
     1461                GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss);
     1462
     1463                vx_input->GetParameterValue(&u, gauss);
     1464                vy_input->GetParameterValue(&v, gauss);
     1465                vz_input->GetParameterValue(&w, gauss);
     1466
     1467                D_scalar_advec=gauss->weight*Jdet;
     1468                if(dt) D_scalar_advec=D_scalar_advec*dt;
     1469
     1470                D[0][0]=D_scalar_advec*u;D[0][1]=0;         D[0][2]=0;
     1471                D[1][0]=0;         D[1][1]=D_scalar_advec*v;D[1][2]=0;
     1472                D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar_advec*w;
     1473
     1474                TripleMultiply(&B_advec[0][0],3,numdof,1,
     1475                                        &D[0][0],3,3,0,
     1476                                        &Bprime_advec[0][0],3,numdof,0,
     1477                                        &Ke_gaussian_advec[0][0],0);
     1478
     1479                /*Transient: */
     1480
     1481                if(dt){
     1482                        GetNodalFunctionsP1(&L[0], gauss);
     1483                        D_scalar_trans=gauss->weight*Jdet;
     1484                        D_scalar_trans=D_scalar_trans;
     1485
     1486                        TripleMultiply(&L[0],numdof,1,0,
     1487                                                &D_scalar_trans,1,1,0,
     1488                                                &L[0],1,numdof,0,
     1489                                                &Ke_gaussian_transient[0][0],0);
     1490                }
     1491                else{
     1492                        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_transient[i][j]=0;
     1493                }
     1494
     1495                /*Artifficial diffusivity*/
     1496
     1497                if(artdiff==1){
     1498                        /*Build K: */
     1499                        D_scalar_artdiff=gauss->weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
     1500                        if(dt) D_scalar_artdiff=D_scalar_artdiff*dt;
     1501                        K[0][0]=D_scalar_artdiff*pow(u,2);       K[0][1]=D_scalar_artdiff*fabs(u)*fabs(v);
     1502                        K[1][0]=D_scalar_artdiff*fabs(u)*fabs(v);K[1][1]=D_scalar_artdiff*pow(v,2);
     1503
     1504                        GetBArtdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss);
     1505
     1506                        TripleMultiply(&B_artdiff[0][0],2,numdof,1,
     1507                                                &K[0][0],2,2,0,
     1508                                                &B_artdiff[0][0],2,numdof,0,
     1509                                                &Ke_gaussian_artdiff[0][0],0);
     1510                }
     1511                else if(artdiff==2){
     1512
     1513                        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
     1514
     1515                        tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
     1516
     1517                        for(i=0;i<numdof;i++){
     1518                                for(j=0;j<numdof;j++){
     1519                                        Ke_gaussian_artdiff[i][j]=tau_parameter*D_scalar_advec*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i])*(u*dh1dh6[0][j]+v*dh1dh6[1][j]+w*dh1dh6[2][j]);
     1520                                }
     1521                        }
     1522                        if(dt){
     1523                                for(i=0;i<numdof;i++){
     1524                                        for(j=0;j<numdof;j++){
     1525                                                Ke_gaussian_artdiff[i][j]+=tau_parameter*D_scalar_trans*L[j]*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
     1526                                        }
     1527                                }
     1528                        }
     1529                }
     1530                else{
     1531                        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_artdiff[i][j]=0;
     1532                }
     1533
     1534                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
     1535        }
     1536
     1537        /*Clean up and return*/
     1538        delete gauss;
     1539        return Ke;
     1540}
     1541/*}}}*/
     1542/*FUNCTION Penta::CreateKMatrixThermalShelf {{{1*/
     1543ElementMatrix* Penta::CreateKMatrixThermalShelf(void){
     1544
     1545        if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
     1546
     1547        /*Call Tria function*/
     1548        Tria* tria=(Tria*)SpawnTria(0,1,2);
     1549        ElementMatrix* Ke=tria->CreateKMatrixThermal();
     1550        delete tria->matice; delete tria;
     1551
     1552        return Ke;
    9461553}
    9471554/*}}}*/
     
    10011608}
    10021609/*}}}*/
     1610/*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
     1611ElementVector* Penta::CreatePVectorAdjointHoriz(void){
     1612
     1613        int approximation;
     1614        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1615
     1616        switch(approximation){
     1617                case MacAyealApproximationEnum:
     1618                        return CreatePVectorAdjointMacAyeal();
     1619                case PattynApproximationEnum:
     1620                        return CreatePVectorAdjointPattyn();
     1621                case NoneApproximationEnum:
     1622                        return NULL;
     1623                case StokesApproximationEnum:
     1624                        return CreatePVectorAdjointStokes();
     1625                default:
     1626                        ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
     1627        }
     1628}
     1629/*}}}*/
     1630/*FUNCTION Penta::CreatePVectorAdjointMacAyeal{{{1*/
     1631ElementVector* Penta::CreatePVectorAdjointMacAyeal(){
     1632
     1633        if (!IsOnBed() || IsOnWater()) return NULL;
     1634
     1635        /*Call Tria function*/
     1636        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1637        ElementVector* pe=tria->CreatePVectorAdjointHoriz();
     1638        delete tria->matice; delete tria;
     1639
     1640        /*clean up and return*/
     1641        return pe;
     1642}
     1643/*}}}*/
     1644/*FUNCTION Penta::CreatePVectorAdjointPattyn{{{1*/
     1645ElementVector* Penta::CreatePVectorAdjointPattyn(void){
     1646
     1647        if (!IsOnSurface() || IsOnWater()) return NULL;
     1648
     1649        /*Call Tria function*/
     1650        Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     1651        ElementVector* pe=tria->CreatePVectorAdjointHoriz();
     1652        delete tria->matice; delete tria;
     1653
     1654        /*clean up and return*/
     1655        return pe;
     1656}
     1657/*}}}*/
     1658/*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
     1659ElementVector* Penta::CreatePVectorBalancedthickness(void){
     1660
     1661        if (!IsOnBed() || IsOnWater()) return NULL;
     1662
     1663        /*Depth Averaging Vx and Vy*/
     1664        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     1665        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     1666
     1667        /*Call Tria function*/
     1668        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1669        ElementVector* pe=tria->CreatePVectorBalancedthickness();
     1670        delete tria->matice; delete tria;
     1671
     1672        /*Delete Vx and Vy averaged*/
     1673        this->inputs->DeleteInput(VxAverageEnum);
     1674        this->inputs->DeleteInput(VyAverageEnum);
     1675
     1676        /*Clean up and return*/
     1677        return pe;
     1678}
     1679/*}}}*/
     1680/*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
     1681ElementVector* Penta::CreatePVectorBalancedvelocities(void){
     1682
     1683        if (!IsOnBed() || IsOnWater()) return NULL;
     1684
     1685        /*Depth Averaging Vx and Vy*/
     1686        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     1687        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     1688
     1689        /*Call Tria function*/
     1690        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1691        ElementVector* pe=tria->CreatePVectorBalancedvelocities();
     1692        delete tria->matice; delete tria;
     1693
     1694        /*Delete Vx and Vy averaged*/
     1695        this->inputs->DeleteInput(VxAverageEnum);
     1696        this->inputs->DeleteInput(VyAverageEnum);
     1697
     1698        /*Clean up and return*/
     1699        return pe;
     1700}
     1701/*}}}*/
     1702/*FUNCTION Penta::CreatePVectorCouplingPattynStokes {{{1*/
     1703ElementVector* Penta::CreatePVectorCouplingPattynStokes(void){
     1704
     1705        /*compute all load vectors for this element*/
     1706        ElementVector* pe1=CreatePVectorCouplingPattynStokesViscous();
     1707        ElementVector* pe2=CreatePVectorCouplingPattynStokesFriction();
     1708        ElementVector* pe =new ElementVector(pe1,pe2);
     1709
     1710        /*clean-up and return*/
     1711        delete pe1;
     1712        delete pe2;
     1713        return pe;
     1714}
     1715/*}}}*/
     1716/*FUNCTION Penta::CreatePVectorCouplingPattynStokesViscous {{{1*/
     1717ElementVector* Penta::CreatePVectorCouplingPattynStokesViscous(void){
     1718
     1719        /*Constants*/
     1720        const int   numdof=NUMVERTICES*NDOF4;
     1721
     1722        /*Intermediaries */
     1723        int         i,j,ig;
     1724        int         approximation;
     1725        double      viscosity,Jdet;
     1726        double      stokesreconditioning;
     1727        double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     1728        double      dw[3];
     1729        double      xyz_list[NUMVERTICES][3];
     1730        double      l1l6[6]; //for the six nodes of the penta
     1731        double      dh1dh6[3][6]; //for the six nodes of the penta
     1732        GaussPenta *gauss=NULL;
     1733
     1734        /*Initialize Element vector and return if necessary*/
     1735        if(IsOnWater()) return NULL;
     1736        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1737        if(approximation!=PattynStokesApproximationEnum) return NULL;
     1738        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     1739
     1740        /*Retrieve all inputs and parameters*/
     1741        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1742        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     1743        Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
     1744        Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
     1745        Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
     1746        Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
     1747
     1748        /* Start  looping on the number of gaussian points: */
     1749        gauss=new GaussPenta(5,5);
     1750        for (ig=gauss->begin();ig<gauss->end();ig++){
     1751
     1752                gauss->GaussPoint(ig);
     1753
     1754                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     1755                GetNodalFunctionsP1(&l1l6[0], gauss);
     1756                GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
     1757
     1758                vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
     1759
     1760                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     1761                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     1762
     1763                for(i=0;i<NUMVERTICES;i++){
     1764                        pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dh1dh6[2][i];
     1765                        pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dh1dh6[2][i];
     1766                        pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dh1dh6[0][i]+dw[1]*dh1dh6[1][i]+2*dw[2]*dh1dh6[2][i]);
     1767                        pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*l1l6[i];
     1768                }
     1769        }
     1770
     1771        /*Clean up and return*/
     1772        delete gauss;
     1773        return pe;
     1774}
     1775/*}}}*/
     1776/*FUNCTION Penta::CreatePVectorCouplingPattynStokesFriction{{{1*/
     1777ElementVector* Penta::CreatePVectorCouplingPattynStokesFriction(void){
     1778
     1779        /*Constants*/
     1780        const int numdof=NUMVERTICES*NDOF4;
     1781
     1782        /*Intermediaries*/
     1783        int         i,j,ig;
     1784        int         approximation,analysis_type;
     1785        double      Jdet,Jdet2d;
     1786        double      stokesreconditioning;
     1787        double     bed_normal[3];
     1788        double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     1789        double      viscosity, w, alpha2_gauss;
     1790        double      dw[3];
     1791        double     xyz_list_tria[NUMVERTICES2D][3];
     1792        double      xyz_list[NUMVERTICES][3];
     1793        double      l1l6[6]; //for the six nodes of the penta
     1794        Tria*       tria=NULL;
     1795        Friction*   friction=NULL;
     1796        GaussPenta  *gauss=NULL;
     1797
     1798        /*Initialize Element vector and return if necessary*/
     1799        if(IsOnWater() || !IsOnBed() || IsOnShelf()) return NULL;
     1800        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1801        if(approximation!=PattynStokesApproximationEnum) return NULL;
     1802        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     1803
     1804        /*Retrieve all inputs and parameters*/
     1805        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1806        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     1807        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     1808        Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
     1809        Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
     1810        Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
     1811        Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
     1812
     1813        for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
     1814
     1815        /*build friction object, used later on: */
     1816        friction=new Friction("3d",inputs,matpar,analysis_type);
     1817
     1818        /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     1819        gauss=new GaussPenta(0,1,2,2);
     1820        for(ig=gauss->begin();ig<gauss->end();ig++){
     1821
     1822                gauss->GaussPoint(ig);
     1823
     1824                GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
     1825                GetNodalFunctionsP1(l1l6, gauss);
     1826
     1827                vzpattyn_input->GetParameterValue(&w, gauss);
     1828                vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
     1829
     1830                BedNormal(&bed_normal[0],xyz_list_tria);
     1831                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     1832                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     1833                friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
     1834
     1835                for(i=0;i<NUMVERTICES2D;i++){
     1836                        pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*l1l6[i];
     1837                        pe->values[i*NDOF4+1]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[1]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[1])*l1l6[i];
     1838                        pe->values[i*NDOF4+2]+=Jdet2d*gauss->weight*2*viscosity*(dw[0]*bed_normal[0]+dw[1]*bed_normal[1]+dw[2]*bed_normal[2])*l1l6[i];
     1839                }
     1840        }
     1841
     1842        /*Clean up and return*/
     1843        delete gauss;
     1844        return pe;
     1845}
     1846/*}}}*/
     1847/*FUNCTION Penta::CreatePVectorDiagnosticHoriz{{{1*/
     1848ElementVector* Penta::CreatePVectorDiagnosticHoriz(void){
     1849
     1850        int approximation;
     1851        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1852
     1853        switch(approximation){
     1854                case MacAyealApproximationEnum:
     1855                        return CreatePVectorDiagnosticMacAyeal();
     1856                case PattynApproximationEnum:
     1857                        return CreatePVectorDiagnosticPattyn();
     1858                case HutterApproximationEnum:
     1859                        return NULL;
     1860                case NoneApproximationEnum:
     1861                        return NULL;
     1862                case StokesApproximationEnum:
     1863                        return CreatePVectorDiagnosticStokes();
     1864                case MacAyealPattynApproximationEnum:
     1865                        return CreatePVectorDiagnosticMacAyealPattyn();
     1866                case PattynStokesApproximationEnum:
     1867                        return CreatePVectorDiagnosticPattynStokes();
     1868                default:
     1869                        ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
     1870        }
     1871}
     1872/*}}}*/
     1873/*FUNCTION Penta::CreatePVectorDiagnosticMacAyealPattyn{{{1*/
     1874ElementVector* Penta::CreatePVectorDiagnosticMacAyealPattyn(void){
     1875
     1876        /*compute all load vectors for this element*/
     1877        ElementVector* pe1=CreatePVectorDiagnosticMacAyeal();
     1878        ElementVector* pe2=CreatePVectorDiagnosticPattyn();
     1879        ElementVector* pe =new ElementVector(pe1,pe2);
     1880
     1881        /*clean-up and return*/
     1882        delete pe1;
     1883        delete pe2;
     1884        return pe;
     1885}
     1886/*}}}*/
     1887/*FUNCTION Penta::CreatePVectorDiagnosticPattynStokes{{{1*/
     1888ElementVector* Penta::CreatePVectorDiagnosticPattynStokes(void){
     1889
     1890        /*compute all load vectors for this element*/
     1891        ElementVector* pe1=CreatePVectorDiagnosticPattyn();
     1892        ElementVector* pe2=CreatePVectorDiagnosticStokes();
     1893        ElementVector* pe3=CreatePVectorCouplingPattynStokes();
     1894        ElementVector* pe =new ElementVector(pe1,pe2,pe3);
     1895
     1896        /*clean-up and return*/
     1897        delete pe1;
     1898        delete pe2;
     1899        delete pe3;
     1900        return pe;
     1901}
     1902/*}}}*/
     1903/*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
     1904ElementVector* Penta::CreatePVectorDiagnosticHutter(void){
     1905
     1906        /*Constants*/
     1907        const int numdofs=NDOF2*NUMVERTICES;
     1908
     1909        /*Intermediaries*/
     1910        int          i,j,k,ig;
     1911        int          node0,node1;
     1912        int          connectivity[2];
     1913        double       Jdet;
     1914        double       xyz_list[NUMVERTICES][3];
     1915        double       xyz_list_segment[2][3];
     1916        double       z_list[NUMVERTICES];
     1917        double       z_segment[2],slope[2];
     1918        double       slope2,constant_part;
     1919        double       rho_ice,gravity,n,B;
     1920        double       ub,vb,z_g,surface,thickness;
     1921        GaussPenta*  gauss=NULL;
     1922
     1923        /*Initialize Element vector and return if necessary*/
     1924        if(IsOnWater()) return NULL;
     1925        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1926
     1927        /*Retrieve all inputs and parameters*/
     1928        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1929        rho_ice=matpar->GetRhoIce();
     1930        gravity=matpar->GetG();
     1931        n=matice->GetN();
     1932        B=matice->GetB();
     1933        Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
     1934        Input* surface_input=inputs->GetInput(SurfaceEnum);      ISSMASSERT(surface_input);
     1935        Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
     1936        Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
     1937        for(i=0;i<NUMVERTICES;i++)z_list[i]=xyz_list[i][2];
     1938
     1939        /*Loop on the three segments*/
     1940        for(i=0;i<3;i++){
     1941                node0=i;
     1942                node1=i+3;
     1943
     1944                for(j=0;j<3;j++){
     1945                        xyz_list_segment[0][j]=xyz_list[node0][j];
     1946                        xyz_list_segment[1][j]=xyz_list[node1][j];
     1947                }
     1948
     1949                connectivity[0]=nodes[node0]->GetConnectivity();
     1950                connectivity[1]=nodes[node1]->GetConnectivity();
     1951
     1952                /*Loop on the Gauss points: */
     1953                gauss=new GaussPenta(node0,node1,3);
     1954                for(ig=gauss->begin();ig<gauss->end();ig++){
     1955                        gauss->GaussPoint(ig);
     1956
     1957                        slopex_input->GetParameterValue(&slope[0],gauss);
     1958                        slopey_input->GetParameterValue(&slope[1],gauss);
     1959                        surface_input->GetParameterValue(&surface,gauss);
     1960                        thickness_input->GetParameterValue(&thickness,gauss);
     1961
     1962                        slope2=pow(slope[0],2)+pow(slope[1],2);
     1963                        constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
     1964
     1965                        PentaRef::GetParameterValue(&z_g,&z_list[0],gauss);
     1966                        GetSegmentJacobianDeterminant(&Jdet,&xyz_list_segment[0][0],gauss);
     1967
     1968                        if (IsOnSurface()){
     1969                                for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight/(double)connectivity[1];
     1970                        }
     1971                        else{//connectivity is too large, should take only half on it
     1972                                for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight*2/(double)connectivity[1];
     1973                        }
     1974                }
     1975                delete gauss;
     1976
     1977                //Deal with lower surface
     1978                if (IsOnBed()){
     1979                        constant_part=-1.58*pow((double)10.0,-(double)10.0)*rho_ice*gravity*thickness;
     1980                        ub=constant_part*slope[0];
     1981                        vb=constant_part*slope[1];
     1982
     1983                        pe->values[2*node0]+=ub/(double)connectivity[0];
     1984                        pe->values[2*node0+1]+=vb/(double)connectivity[0];
     1985                }
     1986        }
     1987
     1988        /*Clean up and return*/
     1989        return pe;
     1990}
     1991/*}}}*/
     1992/*FUNCTION Penta::CreatePVectorDiagnosticMacAyeal{{{1*/
     1993ElementVector* Penta::CreatePVectorDiagnosticMacAyeal(void){
     1994
     1995        if (!IsOnBed() || IsOnWater()) return NULL;
     1996
     1997        /*Call Tria function*/
     1998        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1999        ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
     2000        delete tria->matice; delete tria;
     2001
     2002        /*Clean up and return*/
     2003        return pe;
     2004}
     2005/*}}}*/
     2006/*FUNCTION Penta::CreatePVectorDiagnosticPattyn{{{1*/
     2007ElementVector* Penta::CreatePVectorDiagnosticPattyn(void){
     2008
     2009        /*Constants*/
     2010        const int    numdof=NDOF2*NUMVERTICES;
     2011
     2012        /*Intermediaries*/
     2013        int         i,j,ig;
     2014        double      Jdet;
     2015        double      slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
     2016        double      driving_stress_baseline,thickness;
     2017        double      xyz_list[NUMVERTICES][3];
     2018        double      l1l6[6];
     2019        GaussPenta  *gauss=NULL;
     2020
     2021        /*Initialize Element vector and return if necessary*/
     2022        if(IsOnWater()) return NULL;
     2023        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
     2024
     2025        /*Retrieve all inputs and parameters*/
     2026        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2027        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     2028        Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
     2029
     2030        /* Start  looping on the number of gaussian points: */
     2031        gauss=new GaussPenta(2,3);
     2032        for (ig=gauss->begin();ig<gauss->end();ig++){
     2033
     2034                gauss->GaussPoint(ig);
     2035
     2036                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     2037                GetNodalFunctionsP1(l1l6, gauss);
     2038
     2039                thickness_input->GetParameterValue(&thickness, gauss);
     2040                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     2041
     2042                driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
     2043
     2044                for(i=0;i<NUMVERTICES;i++) for(j=0;j<NDOF2;j++) pe->values[i*NDOF2+j]+= -driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l6[i];
     2045        }
     2046
     2047        /*Clean up and return*/
     2048        delete gauss;
     2049        return pe;
     2050}
     2051/*}}}*/
     2052/*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
     2053ElementVector* Penta::CreatePVectorDiagnosticStokes(void){
     2054
     2055        /*compute all load vectors for this element*/
     2056        ElementVector* pe1=CreatePVectorDiagnosticStokesViscous();
     2057        ElementVector* pe2=CreatePVectorDiagnosticStokesShelf();
     2058        ElementVector* pe =new ElementVector(pe1,pe2);
     2059
     2060        /*clean-up and return*/
     2061        delete pe1;
     2062        delete pe2;
     2063        return pe;
     2064}
     2065/*}}}*/
     2066/*FUNCTION Penta::CreatePVectorDiagnosticStokesViscous {{{1*/
     2067ElementVector* Penta::CreatePVectorDiagnosticStokesViscous(void){
     2068
     2069        /*Constants*/
     2070        const int numdofbubble=NDOF4*NUMVERTICES+NDOF3*1;
     2071
     2072        /*Intermediaries*/
     2073        int        i,j,ig;
     2074        int        approximation;
     2075        double     Jdet,viscosity;
     2076        double     gravity,rho_ice,stokesreconditioning;
     2077        double     xyz_list[NUMVERTICES][3];
     2078        double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     2079        double     l1l7[7]; //for the six nodes and the bubble
     2080        double     B[8][numdofbubble];
     2081        double     B_prime[8][numdofbubble];
     2082        double     B_prime_bubble[8][3];
     2083        double     D[8][8]={0.0};
     2084        double     D_scalar;
     2085        double     Pe_gaussian[numdofbubble]={0.0}; //for the six nodes and the bubble
     2086        double     Ke_temp[numdofbubble][3]={0.0}; //for the six nodes and the bubble
     2087        double     Ke_gaussian[numdofbubble][3];
     2088        GaussPenta *gauss=NULL;
     2089
     2090        /*Initialize Element vector and return if necessary*/
     2091        if(IsOnWater()) return NULL;
     2092        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2093        if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
     2094        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     2095
     2096        /*Retrieve all inputs and parameters*/
     2097        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     2098        rho_ice=matpar->GetRhoIce();
     2099        gravity=matpar->GetG();
     2100        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2101        Input* vx_input=inputs->GetInput(VxEnum);   ISSMASSERT(vx_input);
     2102        Input* vy_input=inputs->GetInput(VyEnum);   ISSMASSERT(vy_input);
     2103        Input* vz_input=inputs->GetInput(VzEnum);   ISSMASSERT(vz_input);
     2104
     2105        /* Start  looping on the number of gaussian points: */
     2106        gauss=new GaussPenta(5,5);
     2107        for (ig=gauss->begin();ig<gauss->end();ig++){
     2108
     2109                gauss->GaussPoint(ig);
     2110
     2111                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     2112                GetBStokes(&B[0][0],&xyz_list[0][0],gauss);
     2113                GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss);
     2114                GetNodalFunctionsMINI(&l1l7[0], gauss);
     2115
     2116                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     2117                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     2118
     2119                for(i=0;i<NUMVERTICES+1;i++){
     2120                        Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
     2121                }
     2122
     2123                /*Get bubble part of Bprime */
     2124                for(i=0;i<8;i++) for(j=0;j<3;j++) B_prime_bubble[i][j]=B_prime[i][j+24];
     2125
     2126                D_scalar=gauss->weight*Jdet;
     2127                for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
     2128                for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
     2129
     2130                TripleMultiply(&B[0][0],8,numdofbubble,1,
     2131                                        &D[0][0],8,8,0,
     2132                                        &B_prime_bubble[0][0],8,3,0,
     2133                                        &Ke_gaussian[0][0],0);
     2134
     2135                for(i=0;i<numdofbubble;i++) for(j=0;j<NDOF3;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
     2136        }
     2137
     2138        /*Condensation*/
     2139        ReduceVectorStokes(pe->values, &Ke_temp[0][0], &Pe_gaussian[0]);
     2140
     2141        /*Clean up and return*/
     2142        delete gauss;
     2143        return pe;
     2144}
     2145/*}}}*/
     2146/*FUNCTION Penta::CreatePVectorDiagnosticStokesShelf{{{1*/
     2147ElementVector* Penta::CreatePVectorDiagnosticStokesShelf(void){
     2148
     2149        /*Intermediaries*/
     2150        int         i,j,ig;
     2151        int         approximation;
     2152        double      gravity,rho_water,bed,water_pressure;
     2153        double          xyz_list_tria[NUMVERTICES2D][3];
     2154        double      xyz_list[NUMVERTICES][3];
     2155        double          bed_normal[3];
     2156        double      l1l6[6]; //for the six nodes of the penta
     2157        double      Jdet2d;
     2158        GaussPenta  *gauss=NULL;
     2159
     2160        /*Initialize Element vector and return if necessary*/
     2161        if(IsOnWater() || !IsOnBed() || !IsOnShelf()) return NULL;
     2162        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2163        if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
     2164        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     2165
     2166        /*Retrieve all inputs and parameters*/
     2167        rho_water=matpar->GetRhoWater();
     2168        gravity=matpar->GetG();
     2169        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2170        Input* bed_input=inputs->GetInput(BedEnum); ISSMASSERT(bed_input);
     2171
     2172        for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
     2173
     2174        /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     2175        gauss=new GaussPenta(0,1,2,2);
     2176        for(ig=gauss->begin();ig<gauss->end();ig++){
     2177
     2178                gauss->GaussPoint(ig);
     2179
     2180                GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
     2181                GetNodalFunctionsP1(l1l6, gauss);
     2182
     2183                bed_input->GetParameterValue(&bed, gauss);
     2184                BedNormal(&bed_normal[0],xyz_list_tria);
     2185                water_pressure=gravity*rho_water*bed;
     2186
     2187                for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) pe->values[i*NDOF4+j]+=water_pressure*gauss->weight*Jdet2d*l1l6[i]*bed_normal[j];
     2188        }
     2189
     2190        /*Clean up and return*/
     2191        delete gauss;
     2192        return pe;
     2193}
     2194/*}}}*/
     2195/*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
     2196ElementVector* Penta::CreatePVectorAdjointStokes(void){
     2197
     2198        if (!IsOnSurface() || IsOnWater()) return NULL;
     2199
     2200        /*Call Tria function*/
     2201        Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     2202        ElementVector* pe=tria->CreatePVectorAdjointStokes();
     2203        delete tria->matice; delete tria;
     2204
     2205        /*clean up and return*/
     2206        return pe;
     2207}
     2208/*}}}*/
     2209/*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
     2210ElementVector* Penta::CreatePVectorDiagnosticVert(void){
     2211
     2212        /*compute all load vectors for this element*/
     2213        ElementVector* pe1=CreatePVectorDiagnosticVertVolume();
     2214        ElementVector* pe2=CreatePVectorDiagnosticVertBase();
     2215        ElementVector* pe =new ElementVector(pe1,pe2);
     2216
     2217        /*clean-up and return*/
     2218        delete pe1;
     2219        delete pe2;
     2220        return pe;
     2221}
     2222/*}}}*/
     2223/*FUNCTION Penta::CreatePVectorDiagnosticVertVolume {{{1*/
     2224ElementVector* Penta::CreatePVectorDiagnosticVertVolume(void){
     2225
     2226        /*Constants*/
     2227        const int  numdof=NDOF1*NUMVERTICES;
     2228
     2229        /*Intermediaries*/
     2230        int        i,ig;
     2231        int        approximation;
     2232        double     Jdet;
     2233        double     xyz_list[NUMVERTICES][3];
     2234        double     dudx,dvdy,dwdz;
     2235        double     du[3],dv[3],dw[3];
     2236        double     l1l6[6];
     2237        GaussPenta *gauss=NULL;
     2238
     2239        /*Initialize Element vector and return if necessary*/
     2240        if(IsOnWater()) return NULL;
     2241        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2242
     2243        /*Retrieve all inputs and parameters*/
     2244        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2245        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2246        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2247        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2248        Input* vzstokes_input=NULL;
     2249        if(approximation==PattynStokesApproximationEnum){
     2250                vzstokes_input=inputs->GetInput(VzStokesEnum); ISSMASSERT(vzstokes_input);
     2251        }
     2252
     2253        /* Start  looping on the number of gaussian points: */
     2254        gauss=new GaussPenta(2,2);
     2255        for (ig=gauss->begin();ig<gauss->end();ig++){
     2256
     2257                gauss->GaussPoint(ig);
     2258
     2259                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     2260                GetNodalFunctionsP1(l1l6, gauss);
     2261
     2262                vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss);
     2263                vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss);
     2264                if(approximation==PattynStokesApproximationEnum){
     2265                        vzstokes_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
     2266                        dwdz=dw[2];
     2267                }
     2268                else dwdz=0;
     2269                dudx=du[0];
     2270                dvdy=dv[1];
     2271
     2272                for (i=0;i<numdof;i++) pe->values[i] += (dudx+dvdy+dwdz)*Jdet*gauss->weight*l1l6[i];
     2273        }
     2274
     2275        /*Clean up and return*/
     2276        delete gauss;
     2277        return pe;
     2278}
     2279/*}}}*/
     2280/*FUNCTION Penta::CreatePVectorDiagnosticVertBase {{{1*/
     2281ElementVector* Penta::CreatePVectorDiagnosticVertBase(void){
     2282
     2283        if (!IsOnBed() || IsOnWater()) return NULL;
     2284
     2285        /*Call Tria function*/
     2286        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2287        ElementVector* pe=tria->CreatePVectorDiagnosticBaseVert();
     2288        delete tria->matice; delete tria;
     2289
     2290        /*Clean up and return*/
     2291        return pe;
     2292}
     2293/*}}}*/
     2294/*FUNCTION Penta::CreatePVectorMelting {{{1*/
     2295ElementVector* Penta::CreatePVectorMelting(void){
     2296        return NULL;
     2297}
     2298/*}}}*/
     2299/*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
     2300ElementVector* Penta::CreatePVectorPrognostic(void){
     2301
     2302        if (!IsOnBed() || IsOnWater()) return NULL;
     2303
     2304        /*Depth Averaging Vx and Vy*/
     2305        this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
     2306        this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
     2307
     2308        /*Call Tria function*/
     2309        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2310        ElementVector* pe=tria->CreatePVectorPrognostic();
     2311        delete tria->matice; delete tria;
     2312
     2313        /*Delete Vx and Vy averaged*/
     2314        this->inputs->DeleteInput(VxAverageEnum);
     2315        this->inputs->DeleteInput(VyAverageEnum);
     2316
     2317        /*Clean up and return*/
     2318        return pe;
     2319}
     2320/*}}}*/
     2321/*FUNCTION Penta::CreatePVectorSlope {{{1*/
     2322ElementVector* Penta::CreatePVectorSlope(void){
     2323
     2324        if (!IsOnBed() || IsOnWater()) return NULL;
     2325
     2326        /*Call Tria function*/
     2327        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2328        ElementVector* pe=tria->CreatePVectorSlope();
     2329        delete tria->matice; delete tria;
     2330
     2331        /*clean up and return*/
     2332        return pe;
     2333}
     2334/*}}}*/
     2335/*FUNCTION Penta::CreatePVectorThermal {{{1*/
     2336ElementVector* Penta::CreatePVectorThermal(void){
     2337
     2338        /*compute all load vectors for this element*/
     2339        ElementVector* pe1=CreatePVectorThermalVolume();
     2340        ElementVector* pe2=CreatePVectorThermalSheet();
     2341        ElementVector* pe3=CreatePVectorThermalShelf();
     2342        ElementVector* pe =new ElementVector(pe1,pe2,pe3);
     2343
     2344        /*clean-up and return*/
     2345        delete pe1;
     2346        delete pe2;
     2347        delete pe3;
     2348        return pe;
     2349}
     2350/*}}}*/
     2351/*FUNCTION Penta::CreatePVectorThermalVolume {{{1*/
     2352ElementVector* Penta::CreatePVectorThermalVolume(void){
     2353
     2354        /*Constants*/
     2355        const int  numdof=NUMVERTICES*NDOF1;
     2356
     2357        /*Intermediaries*/
     2358        int    i,j,ig,found=0;
     2359        int    friction_type,artdiff;
     2360        double Jdet,phi,dt;
     2361        double rho_ice,heatcapacity;
     2362        double thermalconductivity;
     2363        double viscosity,temperature;
     2364        double tau_parameter,diameter;
     2365        double u,v,w;
     2366        double scalar_def,scalar_transient;
     2367        double temperature_list[NUMVERTICES];
     2368        double xyz_list[NUMVERTICES][3];
     2369        double L[numdof];
     2370        double dh1dh6[3][6];
     2371        double epsilon[6];
     2372        GaussPenta *gauss=NULL;
     2373
     2374        /*Initialize Element vector and return if necessary*/
     2375        if(IsOnWater()) return NULL;
     2376        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2377
     2378        /*Retrieve all inputs and parameters*/
     2379        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2380        rho_ice=matpar->GetRhoIce();
     2381        heatcapacity=matpar->GetHeatCapacity();
     2382        thermalconductivity=matpar->GetThermalConductivity();
     2383        this->inputs->GetParameterValue(&dt,DtEnum);
     2384        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     2385        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2386        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2387        Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
     2388        Input* temperature_input=NULL;
     2389        if (dt) temperature_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(inputs);
     2390        if (artdiff==2) diameter=MinEdgeLength(xyz_list);
     2391
     2392        /* Start  looping on the number of gaussian points: */
     2393        gauss=new GaussPenta(2,3);
     2394        for (ig=gauss->begin();ig<gauss->end();ig++){
     2395
     2396                gauss->GaussPoint(ig);
     2397
     2398                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
     2399                GetNodalFunctionsP1(&L[0], gauss);
     2400
     2401                this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
     2402                matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     2403                GetPhi(&phi, &epsilon[0], viscosity);
     2404
     2405                scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
     2406                if(dt) scalar_def=scalar_def*dt;
     2407
     2408                for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
     2409
     2410                /* Build transient now */
     2411                if(dt){
     2412                        temperature_input->GetParameterValue(&temperature, gauss);
     2413                        scalar_transient=temperature*Jdet*gauss->weight;
     2414                        for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
     2415                }
     2416
     2417                if(artdiff==2){
     2418                        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
     2419
     2420                        vx_input->GetParameterValue(&u, gauss);
     2421                        vy_input->GetParameterValue(&v, gauss);
     2422                        vz_input->GetParameterValue(&w, gauss);
     2423
     2424                        tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
     2425
     2426                        for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
     2427                        if(dt){
     2428                                for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
     2429                        }
     2430                }
     2431        }
     2432
     2433        /*Clean up and return*/
     2434        delete gauss;
     2435        return pe;
     2436}
     2437/*}}}*/
     2438/*FUNCTION Penta::CreatePVectorThermalShelf {{{1*/
     2439ElementVector* Penta::CreatePVectorThermalShelf(void){
     2440
     2441        /* Ice/ocean heat exchange flux on ice shelf base */
     2442        if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
     2443
     2444        /*Call Tria function*/
     2445        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2446        ElementVector* pe=tria->CreatePVectorThermalShelf();
     2447        delete tria->matice; delete tria;
     2448
     2449        /*Clean up and return*/
     2450        return pe;
     2451}
     2452/*}}}*/
     2453/*FUNCTION Penta::CreatePVectorThermalSheet {{{1*/
     2454ElementVector* Penta::CreatePVectorThermalSheet(void){
     2455
     2456        /* Geothermal flux on ice sheet base and basal friction */
     2457        if (!IsOnBed() || IsOnShelf() || IsOnWater()) return NULL;
     2458
     2459        /*Call Tria function*/
     2460        Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2461        ElementVector* pe=tria->CreatePVectorThermalSheet();
     2462        delete tria->matice; delete tria;
     2463
     2464        /*Clean up and return*/
     2465        return pe;
     2466}
     2467/*}}}*/
     2468/*FUNCTION Penta::DeepEcho{{{1*/
     2469void Penta::DeepEcho(void){
     2470
     2471        int i;
     2472       
     2473        printf("Penta:\n");
     2474        printf("   id: %i\n",id);
     2475        nodes[0]->DeepEcho();
     2476        nodes[1]->DeepEcho();
     2477        nodes[2]->DeepEcho();
     2478        nodes[3]->DeepEcho();
     2479        nodes[4]->DeepEcho();
     2480        nodes[5]->DeepEcho();
     2481        matice->DeepEcho();
     2482        matpar->DeepEcho();
     2483        printf("   neighbor ids: %i-%i\n",neighbors[0]->Id(),neighbors[1]->Id());
     2484        printf("   parameters\n");
     2485        parameters->DeepEcho();
     2486        printf("   inputs\n");
     2487        inputs->DeepEcho();
     2488        printf("   results\n");
     2489        results->DeepEcho();
     2490        return;
     2491}
     2492/*}}}*/
    10032493/*FUNCTION Penta::DeleteResults {{{1*/
    10042494void  Penta::DeleteResults(void){
     
    10082498        this->results=new Results();
    10092499
     2500}
     2501/*}}}*/
     2502/*FUNCTION Penta::Echo{{{1*/
     2503
     2504void Penta::Echo(void){
     2505        this->DeepEcho();
     2506}
     2507/*}}}*/
     2508/*FUNCTION Penta::Enum {{{1*/
     2509int Penta::Enum(void){
     2510
     2511        return PentaEnum;
     2512
     2513}
     2514/*}}}*/
     2515/*FUNCTION Penta::Gradj {{{1*/
     2516void  Penta::Gradj(Vec gradient,int control_type){
     2517
     2518        /*If on water, skip grad (=0): */
     2519        if(IsOnWater())return;
     2520
     2521        if (control_type==DragCoefficientEnum){
     2522                GradjDrag(gradient);
     2523        }
     2524        else if (control_type==RheologyBbarEnum){
     2525                GradjB(gradient);
     2526        }
     2527        else ISSMERROR("control type %s not supported yet: ",EnumToString(control_type));
     2528}
     2529/*}}}*/
     2530/*FUNCTION Penta::GradjB {{{1*/
     2531void  Penta::GradjB(Vec gradient){
     2532
     2533        int              i;
     2534        int              approximation;
     2535        Tria*            tria           =NULL;
     2536        TriaVertexInput* triavertexinput=NULL;
     2537
     2538        /*If on water, skip: */
     2539        if(IsOnWater())return;
     2540        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2541
     2542        if (approximation==MacAyealApproximationEnum){
     2543                /*Bail out element if MacAyeal (2d) and not on bed*/
     2544                if (!IsOnBed()) return;
     2545
     2546                /*This element should be collapsed into a tria element at its base. Create this tria element,
     2547                 * and compute gardj*/
     2548
     2549                /*Depth Average B*/
     2550                this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
     2551
     2552                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     2553                tria->GradjB(gradient);
     2554                delete tria->matice; delete tria;
     2555
     2556                /*delete B average*/
     2557                this->matice->inputs->DeleteInput(RheologyBbarEnum);
     2558        }
     2559        else{
     2560                /*Gradient is computed on bed only (Bbar)*/
     2561                if (!IsOnBed()) return;
     2562
     2563                /*Depth Average B*/
     2564                this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
     2565
     2566                /*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
     2567                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     2568                tria->GradjB(gradient);
     2569                delete tria->matice; delete tria;
     2570
     2571                /*delete B average*/
     2572                this->matice->inputs->DeleteInput(RheologyBbarEnum);
     2573        }
     2574}
     2575/*}}}*/
     2576/*FUNCTION Penta::GradjDrag {{{1*/
     2577void  Penta::GradjDrag(Vec gradient){
     2578
     2579        int              i,approximation;
     2580        double           temp_gradient[6]={0,0,0,0,0,0};
     2581        Tria*            tria=NULL;
     2582        TriaVertexInput* triavertexinput=NULL;
     2583
     2584        /*retrieve inputs :*/
     2585        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2586
     2587        /*If on water, on shelf or not on bed, skip: */
     2588        if(IsOnWater()|| IsOnShelf() || !IsOnBed())return;
     2589
     2590        if (approximation==MacAyealApproximationEnum || approximation==PattynApproximationEnum){
     2591                /*MacAyeal or Pattyn*/
     2592                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2593                tria->GradjDrag(gradient);
     2594                delete tria->matice; delete tria;
     2595        }
     2596        else if (approximation==StokesApproximationEnum){
     2597                /*Stokes*/
     2598                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2599                tria->GradjDragStokes(gradient);
     2600                delete tria->matice; delete tria;
     2601        }
     2602        else if (approximation==NoneApproximationEnum){
     2603                return;
     2604        }
     2605        else ISSMERROR("approximation %s not supported yet",EnumToString(approximation));
     2606}
     2607/*}}}*/
     2608/*FUNCTION Penta::GetBasalElement{{{1*/
     2609Penta* Penta::GetBasalElement(void){
     2610
     2611        /*Output*/
     2612        Penta* penta=NULL;
     2613
     2614        /*Go through all elements till the bed is reached*/
     2615        penta=this;
     2616        for(;;){
     2617                /*Stop if we have reached the surface, else, take lower penta*/
     2618                if (penta->IsOnBed()) break;
     2619
     2620                /* get lower Penta*/
     2621                penta=penta->GetLowerElement();
     2622                ISSMASSERT(penta->Id()!=this->id);
     2623        }
     2624
     2625        /*return output*/
     2626        return penta;
     2627}
     2628/*}}}*/
     2629/*FUNCTION Penta::GetDofList {{{1*/
     2630void  Penta::GetDofList(int** pdoflist,int approximation_enum,int setenum){
     2631
     2632        int  i,j,count=0;
     2633        int  numberofdofs=0;
     2634        int* doflist=NULL;
     2635
     2636        /*First, figure out size of doflist: */
     2637        for(i=0;i<6;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
     2638
     2639        /*Allocate: */
     2640        doflist=(int*)xmalloc(numberofdofs*sizeof(int));
     2641
     2642        /*Populate: */
     2643        count=0;
     2644        for(i=0;i<6;i++){
     2645                nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
     2646                count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
     2647        }
     2648
     2649        /*Assign output pointers:*/
     2650        *pdoflist=doflist;
     2651}
     2652/*}}}*/
     2653/*FUNCTION Penta::GetDofList1 {{{1*/
     2654void  Penta::GetDofList1(int* doflist){
     2655
     2656        int i;
     2657        for(i=0;i<6;i++) doflist[i]=nodes[i]->GetDofList1();
     2658
     2659}
     2660/*}}}*/
     2661/*FUNCTION Penta::GetElementType {{{1*/
     2662int Penta::GetElementType(){
     2663
     2664        /*return PentaRef field*/
     2665        return this->element_type;
     2666}
     2667/*}}}*/
     2668/*FUNCTION Penta::GetLowerElement{{{1*/
     2669Penta* Penta::GetLowerElement(void){
     2670
     2671        Penta* upper_penta=NULL;
     2672
     2673        upper_penta=(Penta*)neighbors[0]; //first one (0) under, second one (1) above
     2674
     2675        return upper_penta;
    10102676}
    10112677/*}}}*/
     
    10192685        }
    10202686        ISSMERROR("Node provided not found among element nodes");
     2687
     2688}
     2689/*}}}*/
     2690/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
     2691void Penta::GetParameterListOnVertices(double* pvalue,int enumtype){
     2692
     2693        /*Intermediaries*/
     2694        double     value[NUMVERTICES];
     2695        GaussPenta *gauss              = NULL;
     2696
     2697        /*Recover input*/
     2698        Input* input=inputs->GetInput(enumtype);
     2699        if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
     2700
     2701        /*Checks in debugging mode*/
     2702        ISSMASSERT(pvalue);
     2703
     2704        /* Start looping on the number of vertices: */
     2705        gauss=new GaussPenta();
     2706        for (int iv=0;iv<NUMVERTICES;iv++){
     2707                gauss->GaussVertex(iv);
     2708                input->GetParameterValue(&pvalue[iv],gauss);
     2709        }
     2710
     2711        /*clean-up*/
     2712        delete gauss;
     2713}
     2714/*}}}*/
     2715/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
     2716void Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
     2717
     2718        /*Intermediaries*/
     2719        double     value[NUMVERTICES];
     2720        GaussPenta *gauss              = NULL;
     2721
     2722        /*Recover input*/
     2723        Input* input=inputs->GetInput(enumtype);
     2724
     2725        /*Checks in debugging mode*/
     2726        ISSMASSERT(pvalue);
     2727
     2728        /* Start looping on the number of vertices: */
     2729        if (input){
     2730                gauss=new GaussPenta();
     2731                for (int iv=0;iv<NUMVERTICES;iv++){
     2732                        gauss->GaussVertex(iv);
     2733                        input->GetParameterValue(&pvalue[iv],gauss);
     2734                }
     2735        }
     2736        else{
     2737                for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
     2738        }
     2739
     2740        /*clean-up*/
     2741        delete gauss;
     2742}
     2743/*}}}*/
     2744/*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
     2745void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
     2746
     2747        Input* input=inputs->GetInput(enumtype);
     2748        if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
     2749
     2750        GaussPenta* gauss=new GaussPenta();
     2751        gauss->GaussVertex(this->GetNodeIndex(node));
     2752
     2753        input->GetParameterValue(pvalue,gauss);
     2754        delete gauss;
     2755}
     2756/*}}}*/
     2757/*FUNCTION Penta::GetPhi {{{1*/
     2758void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
     2759        /*Compute deformational heating from epsilon and viscosity */
     2760
     2761        double epsilon_matrix[3][3];
     2762        double epsilon_eff;
     2763        double epsilon_sqr[3][3];
     2764
     2765        /* Build epsilon matrix */
     2766        epsilon_matrix[0][0]=*(epsilon+0);
     2767        epsilon_matrix[1][0]=*(epsilon+3);
     2768        epsilon_matrix[2][0]=*(epsilon+4);
     2769        epsilon_matrix[0][1]=*(epsilon+3);
     2770        epsilon_matrix[1][1]=*(epsilon+1);
     2771        epsilon_matrix[2][1]=*(epsilon+5);
     2772        epsilon_matrix[0][2]=*(epsilon+4);
     2773        epsilon_matrix[1][2]=*(epsilon+5);
     2774        epsilon_matrix[2][2]=*(epsilon+2);
     2775
     2776        /* Effective value of epsilon_matrix */
     2777        epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
     2778        epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
     2779        epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
     2780        epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
     2781        epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
     2782        epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
     2783        epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
     2784        epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
     2785        epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
     2786        epsilon_eff=1/pow(2,0.5)*pow((epsilon_sqr[0][0]+epsilon_sqr[0][1]+ epsilon_sqr[0][2]+ epsilon_sqr[1][0]+ epsilon_sqr[1][1]+ epsilon_sqr[1][2]+ epsilon_sqr[2][0]+ epsilon_sqr[2][1]+ epsilon_sqr[2][2]),0.5);
     2787
     2788        /*Phi = Tr(sigma * eps)
     2789         *    = Tr(sigma'* eps)
     2790         *    = 2 * eps_eff * sigma'_eff
     2791         *    = 4 * eps_eff ^2*/
     2792        *phi=4*pow(epsilon_eff,2.0)*viscosity;
     2793}
     2794/*}}}*/
     2795/*FUNCTION Penta::GetSidList{{{1*/
     2796void  Penta::GetSidList(int* sidlist){
     2797
     2798        int i;
     2799        for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
    10212800
    10222801}
     
    10562835                ISSMERROR("analysis: %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
    10572836        }
     2837}
     2838/*}}}*/
     2839/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
     2840void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
     2841
     2842        const int    numdof=NDOF2*NUMVERTICES;
     2843
     2844        int          i;
     2845        int          approximation;
     2846        int*         doflist=NULL;
     2847        double       vx,vy;
     2848        double       values[numdof];
     2849        GaussPenta*  gauss;
     2850
     2851        /*Get approximation enum and dof list: */
     2852        inputs->GetParameterValue(&approximation,ApproximationEnum);
     2853        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2854        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2855
     2856        /*If the element is a coupling, do nothing: every grid is also on an other elements
     2857         * (as coupling is between MacAyeal and Pattyn) so the other element will take care of it*/
     2858        GetDofList(&doflist,approximation,GsetEnum);
     2859
     2860        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     2861        /*P1 element only for now*/
     2862        gauss=new GaussPenta();
     2863        for(i=0;i<NUMVERTICES;i++){
     2864
     2865                /*Recover vx and vy*/
     2866                gauss->GaussVertex(i);
     2867                vx_input->GetParameterValue(&vx,gauss);
     2868                vy_input->GetParameterValue(&vy,gauss);
     2869                values[i*NDOF2+0]=vx;
     2870                values[i*NDOF2+1]=vy;
     2871        }
     2872
     2873        /*Add value to global vector*/
     2874        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2875
     2876        /*Free ressources:*/
     2877        delete gauss;
     2878        xfree((void**)&doflist);
     2879}
     2880/*}}}*/
     2881/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
     2882void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
     2883
     2884        const int    numdof=NDOF2*NUMVERTICES;
     2885
     2886        int          i;
     2887        int*         doflist=NULL;
     2888        double       vx,vy;
     2889        double       values[numdof];
     2890        GaussPenta*  gauss=NULL;
     2891
     2892        /*Get dof list: */
     2893        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     2894        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2895        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2896
     2897        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     2898        /*P1 element only for now*/
     2899        gauss=new GaussPenta();
     2900        for(i=0;i<NUMVERTICES;i++){
     2901                /*Recover vx and vy*/
     2902                gauss->GaussVertex(i);
     2903                vx_input->GetParameterValue(&vx,gauss);
     2904                vy_input->GetParameterValue(&vy,gauss);
     2905                values[i*NDOF2+0]=vx;
     2906                values[i*NDOF2+1]=vy;
     2907        }
     2908
     2909        /*Add value to global vector*/
     2910        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2911
     2912        /*Free ressources:*/
     2913        delete gauss;
     2914        xfree((void**)&doflist);
     2915}
     2916/*}}}*/
     2917/*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
     2918void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
     2919
     2920        const int    numdof=NDOF1*NUMVERTICES;
     2921
     2922        int          i;
     2923        int*         doflist=NULL;
     2924        double       vz;
     2925        double       values[numdof];
     2926        GaussPenta*  gauss=NULL;
     2927
     2928        /*Get dof list: */
     2929        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     2930        Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
     2931
     2932        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     2933        /*P1 element only for now*/
     2934        gauss=new GaussPenta();
     2935        for(i=0;i<NUMVERTICES;i++){
     2936                /*Recover vz */
     2937                gauss->GaussVertex(i);
     2938                vz_input->GetParameterValue(&vz,gauss);
     2939                values[i]=vz;
     2940        }
     2941
     2942        /*Add value to global vector*/
     2943        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2944
     2945        /*Free ressources:*/
     2946        delete gauss;
     2947        xfree((void**)&doflist);
     2948}
     2949/*}}}*/
     2950/*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
     2951void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
     2952
     2953        const int    numdof=NDOF4*NUMVERTICES;
     2954
     2955        int          i;
     2956        int*         doflist=NULL;
     2957        double       vx,vy,vz,p;
     2958        double       stokesreconditioning;
     2959        double       values[numdof];
     2960        GaussPenta   *gauss;
     2961
     2962        /*Get dof list: */
     2963        GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
     2964        Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
     2965        Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
     2966        Input* vz_input=inputs->GetInput(VzEnum);       ISSMASSERT(vz_input);
     2967        Input* p_input =inputs->GetInput(PressureEnum); ISSMASSERT(p_input);
     2968
     2969        /*Recondition pressure: */
     2970        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     2971
     2972        /*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
     2973        /*P1 element only for now*/
     2974        gauss=new GaussPenta();
     2975        for(i=0;i<NUMVERTICES;i++){
     2976                gauss->GaussVertex(i);
     2977                vx_input->GetParameterValue(&vx,gauss);
     2978                vy_input->GetParameterValue(&vy,gauss);
     2979                vz_input->GetParameterValue(&vz,gauss);
     2980                p_input ->GetParameterValue(&p ,gauss);
     2981                values[i*NDOF4+0]=vx;
     2982                values[i*NDOF4+1]=vy;
     2983                values[i*NDOF4+2]=vz;
     2984                values[i*NDOF4+3]=p/stokesreconditioning;
     2985        }
     2986
     2987        /*Add value to global vector*/
     2988        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2989
     2990        /*Free ressources:*/
     2991        delete gauss;
     2992        xfree((void**)&doflist);
     2993}
     2994/*}}}*/
     2995/*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
     2996void  Penta::GetSolutionFromInputsThermal(Vec solution){
     2997
     2998        const int    numdof=NDOF1*NUMVERTICES;
     2999
     3000        int          i;
     3001        int*         doflist=NULL;
     3002        double       values[numdof];
     3003        double       temp;
     3004        GaussPenta   *gauss=NULL;
     3005
     3006        /*Get dof list: */
     3007        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3008        Input* t_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(t_input);
     3009
     3010        gauss=new GaussPenta();
     3011        for(i=0;i<NUMVERTICES;i++){
     3012                /*Recover temperature*/
     3013                gauss->GaussVertex(i);
     3014                t_input->GetParameterValue(&temp,gauss);
     3015                values[i]=temp;
     3016        }
     3017
     3018        /*Add value to global vector*/
     3019        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     3020
     3021        /*Free ressources:*/
     3022        delete gauss;
     3023        xfree((void**)&doflist);
     3024}
     3025/*}}}*/
     3026/*FUNCTION Penta::GetStabilizationParameter {{{1*/
     3027double Penta::GetStabilizationParameter(double u, double v, double w, double diameter, double rho_ice, double heatcapacity, double thermalconductivity){
     3028        /*Compute stabilization parameter*/
     3029
     3030        double normu;
     3031        double tau_parameter;
     3032
     3033        normu=pow(pow(u,2)+pow(v,2)+pow(w,2),0.5);
     3034        if(normu*diameter/(3*2*thermalconductivity/(rho_ice*heatcapacity))<1){
     3035                tau_parameter=pow(diameter,2)/(3*2*2*thermalconductivity/(rho_ice*heatcapacity));
     3036        }
     3037        else tau_parameter=diameter/(2*normu);
     3038
     3039        return tau_parameter;
     3040}
     3041/*}}}*/
     3042/*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
     3043void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input){
     3044        /*Compute the 3d Blatter/PattynStrain Rate (5 components):
     3045         *
     3046         * epsilon=[exx eyy exy exz eyz]
     3047         *
     3048         * with exz=1/2 du/dz
     3049         *      eyz=1/2 dv/dz
     3050         *
     3051         * the contribution of vz is neglected
     3052         */
     3053
     3054        int i;
     3055        double epsilonvx[5];
     3056        double epsilonvy[5];
     3057
     3058        /*Check that both inputs have been found*/
     3059        if (!vx_input || !vy_input){
     3060                ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
     3061        }
     3062
     3063        /*Get strain rate assuming that epsilon has been allocated*/
     3064        vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
     3065        vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
     3066
     3067        /*Sum all contributions*/
     3068        for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
     3069}
     3070/*}}}*/
     3071/*FUNCTION Penta::GetStrainRate3d{{{1*/
     3072void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
     3073        /*Compute the 3d Strain Rate (6 components):
     3074         *
     3075         * epsilon=[exx eyy ezz exy exz eyz]
     3076         */
     3077
     3078        int i;
     3079        double epsilonvx[6];
     3080        double epsilonvy[6];
     3081        double epsilonvz[6];
     3082
     3083        /*Check that both inputs have been found*/
     3084        if (!vx_input || !vy_input || !vz_input){
     3085                ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
     3086        }
     3087
     3088        /*Get strain rate assuming that epsilon has been allocated*/
     3089        vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
     3090        vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
     3091        vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
     3092
     3093        /*Sum all contributions*/
     3094        for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
     3095}
     3096/*}}}*/
     3097/*FUNCTION Penta::GetUpperElement{{{1*/
     3098Penta* Penta::GetUpperElement(void){
     3099
     3100        Penta* upper_penta=NULL;
     3101
     3102        upper_penta=(Penta*)neighbors[1]; //first one under, second one above
     3103
     3104        return upper_penta;
    10583105}
    10593106/*}}}*/
     
    10763123}
    10773124/*}}}*/
    1078 /*FUNCTION Penta::Gradj {{{1*/
    1079 void  Penta::Gradj(Vec gradient,int control_type){
    1080 
    1081         /*If on water, skip grad (=0): */
    1082         if(IsOnWater())return;
    1083 
    1084         if (control_type==DragCoefficientEnum){
    1085                 GradjDrag(gradient);
    1086         }
    1087         else if (control_type==RheologyBbarEnum){
    1088                 GradjB(gradient);
    1089         }
    1090         else ISSMERROR("control type %s not supported yet: ",EnumToString(control_type));
     3125/*FUNCTION Penta::GetZcoord {{{1*/
     3126double Penta::GetZcoord(GaussPenta* gauss){
     3127
     3128        int    i;
     3129        double z;
     3130        double xyz_list[NUMVERTICES][3];
     3131        double z_list[NUMVERTICES];
     3132
     3133        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3134        for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[i][2];
     3135        PentaRef::GetParameterValue(&z,z_list,gauss);
     3136
     3137        return z;
     3138}
     3139/*}}}*/
     3140/*FUNCTION Penta::Id {{{1*/
     3141int    Penta::Id(void){
     3142        return id;
     3143}
     3144/*}}}*/
     3145/*FUNCTION Penta::InputArtificialNoise{{{1*/
     3146void  Penta::InputArtificialNoise(int enum_type,double min,double max){
     3147
     3148        Input* input=NULL;
     3149
     3150        /*Make a copy of the original input: */
     3151        input=(Input*)this->inputs->GetInput(enum_type);
     3152        if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
     3153
     3154        /*ArtificialNoise: */
     3155        input->ArtificialNoise(min,max);
    10913156}
    10923157/*}}}*/
     
    12713336}
    12723337/*}}}*/
    1273 /*FUNCTION Penta::InputArtificialNoise{{{1*/
    1274 void  Penta::InputArtificialNoise(int enum_type,double min,double max){
    1275 
    1276         Input* input=NULL;
    1277 
    1278         /*Make a copy of the original input: */
    1279         input=(Input*)this->inputs->GetInput(enum_type);
    1280         if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
    1281 
    1282         /*ArtificialNoise: */
    1283         input->ArtificialNoise(min,max);
     3338/*FUNCTION Penta::InputExtrude {{{1*/
     3339void  Penta::InputExtrude(int enum_type,int object_type){
     3340
     3341        Penta *penta          = NULL;
     3342        Input *original_input = NULL;
     3343
     3344        /*Are we on the base, not on the surface?:*/
     3345        if(IsOnBed()){
     3346                /*OK, we are on bed. we will follow the steps:
     3347                 * 1: find input and extrude it.
     3348                 * 2: follow the upper element until we reach the surface
     3349                 * 3: for each element, we will add a copy of the extruded input*/
     3350
     3351                /*Step1: Extrude the original input: */
     3352                if (object_type==ElementsEnum)
     3353                 original_input=(Input*)this->inputs->GetInput(enum_type);
     3354                else if (object_type==MaterialsEnum)
     3355                 original_input=(Input*)matice->inputs->GetInput(enum_type);
     3356                else
     3357                 ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
     3358                if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumToString(enum_type));
     3359                original_input->Extrude();
     3360
     3361                /*Stop if there is only one layer of element*/
     3362                if (this->IsOnSurface()) return;
     3363
     3364                /*Step 2: this input has been extruded for this element, now follow the upper element*/
     3365                penta=this;
     3366                for(;;){
     3367
     3368                        /* get upper Penta*/
     3369                        penta=penta->GetUpperElement();
     3370                        ISSMASSERT(penta->Id()!=this->id);
     3371
     3372                        /*Add input of the basal element to penta->inputs*/
     3373                        Input* copy=NULL;
     3374                        copy=(Input*)original_input->copy();
     3375                        if (object_type==ElementsEnum)
     3376                         penta->inputs->AddInput((Input*)copy);
     3377                        else if (object_type==MaterialsEnum)
     3378                         penta->matice->inputs->AddInput((Input*)copy);
     3379                        else
     3380                         ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
     3381
     3382                        /*Stop if we have reached the surface*/
     3383                        if (penta->IsOnSurface()) break;
     3384                }
     3385        }
     3386
     3387        return;
    12843388}
    12853389/*}}}*/
     
    13163420}
    13173421/*}}}*/
     3422/*FUNCTION Penta::InputUpdateFromConstant(bool value, int name);{{{1*/
     3423void  Penta::InputUpdateFromConstant(bool constant, int name){
     3424
     3425        /*Check that name is an element input*/
     3426        if (!IsInput(name)) return;
     3427
     3428        /*update input*/
     3429        this->inputs->AddInput(new BoolInput(name,constant));
     3430}
     3431/*}}}*/
     3432/*FUNCTION Penta::InputUpdateFromConstant(double value, int name);{{{1*/
     3433void  Penta::InputUpdateFromConstant(double constant, int name){
     3434        /*Check that name is an element input*/
     3435        if (!IsInput(name)) return;
     3436
     3437        /*update input*/
     3438        this->inputs->AddInput(new DoubleInput(name,constant));
     3439}
     3440/*}}}*/
     3441/*FUNCTION Penta::InputUpdateFromConstant(int value, int name);{{{1*/
     3442void  Penta::InputUpdateFromConstant(int constant, int name){
     3443        /*Check that name is an element input*/
     3444        if (!IsInput(name)) return;
     3445
     3446        /*update input*/
     3447        this->inputs->AddInput(new IntInput(name,constant));
     3448}
     3449/*}}}*/
     3450/*FUNCTION Penta::InputUpdateFromIoModel {{{1*/
     3451void Penta::InputUpdateFromIoModel(int index,IoModel* iomodel){
     3452
     3453        /*Intermediaries*/
     3454        IssmInt i,j;
     3455        int     penta_vertex_ids[6];
     3456        double  nodeinputs[6];
     3457
     3458        /*Checks if debuging*/
     3459        /*{{{2*/
     3460        ISSMASSERT(iomodel->elements);
     3461        /*}}}*/
     3462
     3463        /*Recover vertices ids needed to initialize inputs*/
     3464        for(i=0;i<6;i++){
     3465                penta_vertex_ids[i]=(int)iomodel->elements[6*index+i]; //ids for vertices are in the elements array from Matlab
     3466        }
     3467
     3468        //add as many inputs per element as requested:
     3469        if (iomodel->thickness) {
     3470                for(i=0;i<6;i++)nodeinputs[i]=iomodel->thickness[penta_vertex_ids[i]-1];
     3471                this->inputs->AddInput(new PentaVertexInput(ThicknessEnum,nodeinputs));
     3472        }
     3473        if (iomodel->surface) {
     3474                for(i=0;i<6;i++)nodeinputs[i]=iomodel->surface[penta_vertex_ids[i]-1];
     3475                this->inputs->AddInput(new PentaVertexInput(SurfaceEnum,nodeinputs));
     3476        }
     3477        if (iomodel->bed) {
     3478                for(i=0;i<6;i++)nodeinputs[i]=iomodel->bed[penta_vertex_ids[i]-1];
     3479                this->inputs->AddInput(new PentaVertexInput(BedEnum,nodeinputs));
     3480        }
     3481        if (iomodel->drag_coefficient) {
     3482                for(i=0;i<6;i++)nodeinputs[i]=iomodel->drag_coefficient[penta_vertex_ids[i]-1];
     3483                this->inputs->AddInput(new PentaVertexInput(DragCoefficientEnum,nodeinputs));
     3484
     3485                if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
     3486                if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
     3487                this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
     3488
     3489        }
     3490        if (iomodel->melting_rate) {
     3491                for(i=0;i<6;i++)nodeinputs[i]=iomodel->melting_rate[penta_vertex_ids[i]-1]/iomodel->yts;
     3492                this->inputs->AddInput(new PentaVertexInput(MeltingRateEnum,nodeinputs));
     3493        }
     3494        if (iomodel->accumulation_rate) {
     3495                for(i=0;i<6;i++)nodeinputs[i]=iomodel->accumulation_rate[penta_vertex_ids[i]-1]/iomodel->yts;
     3496                this->inputs->AddInput(new PentaVertexInput(AccumulationRateEnum,nodeinputs));
     3497        }
     3498        if (iomodel->geothermalflux) {
     3499                for(i=0;i<6;i++)nodeinputs[i]=iomodel->geothermalflux[penta_vertex_ids[i]-1];
     3500                this->inputs->AddInput(new PentaVertexInput(GeothermalFluxEnum,nodeinputs));
     3501        }       
     3502        if (iomodel->pressure) {
     3503                for(i=0;i<6;i++)nodeinputs[i]=iomodel->pressure[penta_vertex_ids[i]-1];
     3504                this->inputs->AddInput(new PentaVertexInput(PressureEnum,nodeinputs));
     3505        }
     3506        if (iomodel->temperature) {
     3507                for(i=0;i<6;i++)nodeinputs[i]=iomodel->temperature[penta_vertex_ids[i]-1];
     3508                this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,nodeinputs));
     3509        }
     3510        if (iomodel->dhdt) {
     3511                for(i=0;i<6;i++)nodeinputs[i]=iomodel->dhdt[penta_vertex_ids[i]-1]/iomodel->yts;
     3512                this->inputs->AddInput(new PentaVertexInput(DhDtEnum,nodeinputs));
     3513        }
     3514        /*vx,vy and vz: */
     3515        if (iomodel->vx) {
     3516                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx[penta_vertex_ids[i]-1]/iomodel->yts;
     3517                this->inputs->AddInput(new PentaVertexInput(VxEnum,nodeinputs));
     3518                this->inputs->AddInput(new PentaVertexInput(VxOldEnum,nodeinputs));
     3519                if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVxEnum,nodeinputs));
     3520        }
     3521        if (iomodel->vy) {
     3522                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy[penta_vertex_ids[i]-1]/iomodel->yts;
     3523                this->inputs->AddInput(new PentaVertexInput(VyEnum,nodeinputs));
     3524                this->inputs->AddInput(new PentaVertexInput(VyOldEnum,nodeinputs));
     3525                if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVyEnum,nodeinputs));
     3526        }
     3527        if (iomodel->vz) {
     3528                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz[penta_vertex_ids[i]-1]/iomodel->yts;
     3529                this->inputs->AddInput(new PentaVertexInput(VzEnum,nodeinputs));
     3530                this->inputs->AddInput(new PentaVertexInput(VzOldEnum,nodeinputs));
     3531                if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVzEnum,nodeinputs));
     3532        }
     3533        if (iomodel->vx_obs) {
     3534                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx_obs[penta_vertex_ids[i]-1]/iomodel->yts;
     3535                this->inputs->AddInput(new PentaVertexInput(VxObsEnum,nodeinputs));
     3536        }
     3537        if (iomodel->vy_obs) {
     3538                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy_obs[penta_vertex_ids[i]-1]/iomodel->yts;
     3539                this->inputs->AddInput(new PentaVertexInput(VyObsEnum,nodeinputs));
     3540        }
     3541        if (iomodel->vz_obs) {
     3542                for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz_obs[penta_vertex_ids[i]-1]/iomodel->yts;
     3543                this->inputs->AddInput(new PentaVertexInput(VzObsEnum,nodeinputs));
     3544        }
     3545        if (iomodel->weights) {
     3546                for(i=0;i<6;i++)nodeinputs[i]=iomodel->weights[penta_vertex_ids[i]-1];
     3547                this->inputs->AddInput(new PentaVertexInput(WeightsEnum,nodeinputs));
     3548        }
     3549        if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
     3550        if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
     3551        if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
     3552        if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
     3553
     3554        /*time: */
     3555        this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
     3556
     3557        /*Control Inputs*/
     3558        if (iomodel->control_analysis && iomodel->control_type){
     3559                for(i=0;i<iomodel->num_control_type;i++){
     3560                        switch((int)iomodel->control_type[i]){
     3561                                case DhDtEnum:
     3562                                        if (iomodel->dhdt){
     3563                                                for(j=0;j<6;j++)nodeinputs[j]=iomodel->dhdt[penta_vertex_ids[j]-1]/iomodel->yts;
     3564                                                this->inputs->AddInput(new ControlInput(DhDtEnum,PentaVertexInputEnum,nodeinputs,i+1));
     3565                                        }
     3566                                        break;
     3567                                case VxEnum:
     3568                                        if (iomodel->vx){
     3569                                                for(j=0;j<6;j++)nodeinputs[j]=iomodel->vx[penta_vertex_ids[j]-1]/iomodel->yts;
     3570                                                this->inputs->AddInput(new ControlInput(VxEnum,PentaVertexInputEnum,nodeinputs,i+1));
     3571                                        }
     3572                                        break;
     3573                                case VyEnum:
     3574                                        if (iomodel->vy){
     3575                                                for(j=0;j<6;j++)nodeinputs[j]=iomodel->vy[penta_vertex_ids[j]-1]/iomodel->yts;
     3576                                                this->inputs->AddInput(new ControlInput(VyEnum,PentaVertexInputEnum,nodeinputs,i+1));
     3577                                        }
     3578                                        break;
     3579                                case DragCoefficientEnum:
     3580                                        if (iomodel->drag_coefficient){
     3581                                                for(j=0;j<6;j++)nodeinputs[j]=iomodel->drag_coefficient[penta_vertex_ids[j]-1];
     3582                                                this->inputs->AddInput(new ControlInput(DragCoefficientEnum,PentaVertexInputEnum,nodeinputs,i+1));
     3583                                        }
     3584                                        break;
     3585                                case RheologyBbarEnum:
     3586                                        /*Matice will take care of it*/ break;
     3587                                default:
     3588                                        ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
     3589                        }
     3590                }
     3591        }
     3592
     3593        //Need to know the type of approximation for this element
     3594        if(iomodel->elements_type){
     3595                if (*(iomodel->elements_type+index)==MacAyealApproximationEnum){
     3596                        this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealApproximationEnum));
     3597                }
     3598                else if (*(iomodel->elements_type+index)==PattynApproximationEnum){
     3599                        this->inputs->AddInput(new IntInput(ApproximationEnum,PattynApproximationEnum));
     3600                }
     3601                else if (*(iomodel->elements_type+index)==MacAyealPattynApproximationEnum){
     3602                        this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealPattynApproximationEnum));
     3603                }
     3604                else if (*(iomodel->elements_type+index)==HutterApproximationEnum){
     3605                        this->inputs->AddInput(new IntInput(ApproximationEnum,HutterApproximationEnum));
     3606                }
     3607                else if (*(iomodel->elements_type+index)==StokesApproximationEnum){
     3608                        this->inputs->AddInput(new IntInput(ApproximationEnum,StokesApproximationEnum));
     3609                }
     3610                else if (*(iomodel->elements_type+index)==PattynStokesApproximationEnum){
     3611                        this->inputs->AddInput(new IntInput(ApproximationEnum,PattynStokesApproximationEnum));
     3612                }
     3613                else if (*(iomodel->elements_type+index)==NoneApproximationEnum){
     3614                        this->inputs->AddInput(new IntInput(ApproximationEnum,NoneApproximationEnum));
     3615                }
     3616                else{
     3617                        ISSMERROR("Approximation type %s not supported yet",EnumToString((int)*(iomodel->elements_type+index)));
     3618                }
     3619        }
     3620
     3621}
     3622/*}}}*/
     3623/*FUNCTION Penta::InputUpdateFromSolution {{{1*/
     3624void  Penta::InputUpdateFromSolution(double* solution){
     3625
     3626        int analysis_type;
     3627
     3628        /*retreive parameters: */
     3629        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     3630
     3631        /*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
     3632        if (analysis_type==DiagnosticHorizAnalysisEnum){
     3633                InputUpdateFromSolutionDiagnosticHoriz( solution);
     3634        }
     3635        else if (analysis_type==DiagnosticHutterAnalysisEnum){
     3636                InputUpdateFromSolutionDiagnosticHutter( solution);
     3637        }
     3638        else if (analysis_type==DiagnosticVertAnalysisEnum){
     3639                InputUpdateFromSolutionDiagnosticVert( solution);
     3640        }
     3641        else if (analysis_type==AdjointHorizAnalysisEnum){
     3642                int approximation;
     3643                inputs->GetParameterValue(&approximation,ApproximationEnum);
     3644                if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
     3645                        InputUpdateFromSolutionAdjointStokes( solution);
     3646                }
     3647                else{
     3648                        InputUpdateFromSolutionAdjointHoriz( solution);
     3649                }
     3650        }
     3651        else if (analysis_type==BedSlopeXAnalysisEnum){
     3652                InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeXEnum);
     3653        }
     3654        else if (analysis_type==BedSlopeYAnalysisEnum){
     3655                InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeYEnum);
     3656        }
     3657        else if (analysis_type==SurfaceSlopeXAnalysisEnum){
     3658                InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeXEnum);
     3659        }
     3660        else if (analysis_type==SurfaceSlopeYAnalysisEnum){
     3661                InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeYEnum);
     3662        }
     3663        else if (analysis_type==PrognosticAnalysisEnum){
     3664                InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
     3665        }
     3666        else if (analysis_type==BalancedthicknessAnalysisEnum){
     3667                InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
     3668        }
     3669        else if (analysis_type==BalancedvelocitiesAnalysisEnum){
     3670                InputUpdateFromSolutionOneDofCollapsed(solution,VelEnum);
     3671        }
     3672        else if (analysis_type==ThermalAnalysisEnum){
     3673                InputUpdateFromSolutionThermal( solution);
     3674        }
     3675        else if (analysis_type==MeltingAnalysisEnum){
     3676                InputUpdateFromSolutionOneDof(solution,MeltingRateEnum);
     3677        }
     3678        else{
     3679                ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
     3680        }
     3681}
     3682/*}}}*/
     3683/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
     3684void  Penta::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
     3685
     3686        int  approximation;
     3687
     3688        /*Recover inputs*/
     3689        inputs->GetParameterValue(&approximation,ApproximationEnum);
     3690
     3691        /*MacAyeal, everything is done by the element on bed*/
     3692        if (approximation==MacAyealApproximationEnum){
     3693                if (!IsOnBed()){
     3694                        /*Do nothing. Element on bed will take care of it*/
     3695                        return;
     3696                }
     3697                else{
     3698                        InputUpdateFromSolutionDiagnosticMacAyeal(solution);
     3699                        return;
     3700                }
     3701        }
     3702        else if (approximation==PattynApproximationEnum){
     3703                InputUpdateFromSolutionDiagnosticPattyn(solution);
     3704        }
     3705        else if (approximation==PattynStokesApproximationEnum){
     3706                InputUpdateFromSolutionDiagnosticPattynStokes(solution);
     3707        }
     3708        else if (approximation==MacAyealStokesApproximationEnum){
     3709                InputUpdateFromSolutionDiagnosticMacAyealStokes(solution);
     3710        }
     3711        else if (approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
     3712                InputUpdateFromSolutionDiagnosticStokes(solution);
     3713        }
     3714        else if (approximation==MacAyealPattynApproximationEnum){
     3715                InputUpdateFromSolutionDiagnosticMacAyealPattyn(solution);
     3716        }
     3717}
     3718/*}}}*/
     3719/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyeal {{{1*/
     3720void  Penta::InputUpdateFromSolutionDiagnosticMacAyeal(double* solution){
     3721
     3722        const int    numdof=NDOF2*NUMVERTICES;
     3723
     3724        int     i,dummy;
     3725        double  rho_ice,g;
     3726        double  values[numdof];
     3727        double  vx[NUMVERTICES];
     3728        double  vy[NUMVERTICES];
     3729        double  vz[NUMVERTICES];
     3730        double  vel[NUMVERTICES];
     3731        double  pressure[NUMVERTICES];
     3732        double  surface[NUMVERTICES];
     3733        double  xyz_list[NUMVERTICES][3];
     3734        int    *doflist = NULL;
     3735        double *vz_ptr  = NULL;
     3736        Penta  *penta   = NULL;
     3737
     3738        /*Get dof list: */
     3739        GetDofList(&doflist,MacAyealApproximationEnum,GsetEnum);
     3740
     3741        /*Use the dof list to index into the solution vector: */
     3742        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3743
     3744        /*Ok, we have vx and vy in values, fill in vx and vy arrays and extrude */
     3745        for(i=0;i<3;i++){
     3746                vx[i]  =values[i*NDOF2+0];
     3747                vy[i]  =values[i*NDOF2+1];
     3748                vx[i+3]=vx[i];
     3749                vy[i+3]=vy[i];
     3750        }
     3751
     3752        /*Get parameters fro pressure computation*/
     3753        rho_ice=matpar->GetRhoIce();
     3754        g=matpar->GetG();
     3755
     3756        /*Start looping over all elements above current element and update all inputs*/
     3757        penta=this;
     3758        for(;;){
     3759
     3760                /*Get node data: */
     3761                GetVerticesCoordinates(&xyz_list[0][0],penta->nodes,NUMVERTICES);
     3762
     3763                /*Now Compute vel*/
     3764                Input* vz_input=inputs->GetInput(VzEnum);
     3765                if (vz_input){
     3766                        if (vz_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
     3767                        vz_input->GetValuesPtr(&vz_ptr,&dummy);
     3768                        for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
     3769                }
     3770                else{for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;}
     3771                for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     3772
     3773                /*Now compute pressure*/
     3774                GetParameterListOnVertices(&surface[0],SurfaceEnum);
     3775                for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
     3776
     3777                /*Now, we have to move the previous Vx and Vy inputs  to old
     3778                 * status, otherwise, we'll wipe them off: */
     3779                penta->inputs->ChangeEnum(VxEnum,VxOldEnum);
     3780                penta->inputs->ChangeEnum(VyEnum,VyOldEnum);
     3781                penta->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     3782
     3783                /*Add vx and vy as inputs to the tria element: */
     3784                penta->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     3785                penta->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     3786                penta->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     3787                penta->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     3788
     3789                /*Stop if we have reached the surface*/
     3790                if (penta->IsOnSurface()) break;
     3791
     3792                /* get upper Penta*/
     3793                penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
     3794        }
     3795       
     3796        /*Free ressources:*/
     3797        xfree((void**)&doflist);
     3798}
     3799/*}}}*/
     3800/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn {{{1*/
     3801void  Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn(double* solution){
     3802
     3803        const int    numdof=NDOF2*NUMVERTICES;
     3804        const int    numdof2d=NDOF2*NUMVERTICES2D;
     3805
     3806        int     i,dummy;
     3807        double  rho_ice,g;
     3808        double  macayeal_values[numdof];
     3809        double  pattyn_values[numdof];
     3810        double  vx[NUMVERTICES];
     3811        double  vy[NUMVERTICES];
     3812        double  vz[NUMVERTICES];
     3813        double  vel[NUMVERTICES];
     3814        double  pressure[NUMVERTICES];
     3815        double  surface[NUMVERTICES];
     3816        double  xyz_list[NUMVERTICES][3];
     3817        int*    doflistp = NULL;
     3818        int*    doflistm = NULL;
     3819        double  *vz_ptr  = NULL;
     3820        Penta   *penta   = NULL;
     3821
     3822        /*OK, we have to add results of this element for pattyn
     3823         * and results from the penta at base for macayeal. Now recover results*/
     3824        penta=GetBasalElement();
     3825
     3826        /*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
     3827        GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
     3828        penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
     3829
     3830        /*Get node data: */
     3831        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3832
     3833        /*Use the dof list to index into the solution vector: */
     3834        for(i=0;i<numdof2d;i++){
     3835                pattyn_values[i]=solution[doflistp[i]];
     3836                macayeal_values[i]=solution[doflistm[i]];
     3837        }
     3838        for(i=numdof2d;i<numdof;i++){
     3839                pattyn_values[i]=solution[doflistp[i]];
     3840                macayeal_values[i]=macayeal_values[i-numdof2d];
     3841        }
     3842
     3843        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3844        for(i=0;i<NUMVERTICES;i++){
     3845                vx[i]=macayeal_values[i*NDOF2+0]+pattyn_values[i*NDOF2+0];
     3846                vy[i]=macayeal_values[i*NDOF2+1]+pattyn_values[i*NDOF2+1];
     3847        }
     3848
     3849        /*Get Vz*/
     3850        Input* vz_input=inputs->GetInput(VzEnum);
     3851        if (vz_input){
     3852                if (vz_input->Enum()!=PentaVertexInputEnum){
     3853                        ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
     3854                }
     3855                vz_input->GetValuesPtr(&vz_ptr,&dummy);
     3856                for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
     3857        }
     3858        else{
     3859                for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
     3860        }
     3861
     3862        /*Now Compute vel*/
     3863        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     3864
     3865        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
     3866         *so the pressure is just the pressure at the z elevation: */
     3867        rho_ice=matpar->GetRhoIce();
     3868        g=matpar->GetG();
     3869        GetParameterListOnVertices(&surface[0],SurfaceEnum);
     3870        for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
     3871
     3872        /*Now, we have to move the previous Vx and Vy inputs  to old
     3873         * status, otherwise, we'll wipe them off: */
     3874        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     3875        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     3876        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     3877
     3878        /*Add vx and vy as inputs to the tria element: */
     3879        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     3880        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     3881        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     3882        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     3883
     3884        /*Free ressources:*/
     3885        xfree((void**)&doflistp);
     3886        xfree((void**)&doflistm);
     3887}
     3888/*}}}*/
     3889/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes {{{1*/
     3890void  Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes(double* solution){
     3891
     3892        const int    numdofm=NDOF2*NUMVERTICES;
     3893        const int    numdofs=NDOF4*NUMVERTICES;
     3894        const int    numdof2d=NDOF2*NUMVERTICES2D;
     3895
     3896        int     i,dummy;
     3897        double  stokesreconditioning;
     3898        double  macayeal_values[numdofm];
     3899        double  stokes_values[numdofs];
     3900        double  vx[NUMVERTICES];
     3901        double  vy[NUMVERTICES];
     3902        double  vz[NUMVERTICES];
     3903        double  vzmacayeal[NUMVERTICES];
     3904        double  vzstokes[NUMVERTICES];
     3905        double  vel[NUMVERTICES];
     3906        double  pressure[NUMVERTICES];
     3907        double  xyz_list[NUMVERTICES][3];
     3908        int*    doflistm        = NULL;
     3909        int*    doflists        = NULL;
     3910        double  *vzmacayeal_ptr = NULL;
     3911        Penta   *penta          = NULL;
     3912
     3913        /*OK, we have to add results of this element for macayeal
     3914         * and results from the penta at base for macayeal. Now recover results*/
     3915        penta=GetBasalElement();
     3916
     3917        /*Get dof listof this element (macayeal dofs) and of the penta at base (macayeal dofs): */
     3918        penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
     3919        GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
     3920        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     3921
     3922        /*Get node data: */
     3923        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3924
     3925        /*Use the dof list to index into the solution vector: */
     3926        for(i=0;i<numdof2d;i++){
     3927                macayeal_values[i]=solution[doflistm[i]];
     3928                macayeal_values[i+numdof2d]=solution[doflistm[i]];
     3929        }
     3930        for(i=0;i<numdofs;i++){
     3931                stokes_values[i]=solution[doflists[i]];
     3932        }
     3933
     3934        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3935        for(i=0;i<NUMVERTICES;i++){
     3936                vx[i]=stokes_values[i*NDOF4+0]+macayeal_values[i*NDOF2+0];
     3937                vy[i]=stokes_values[i*NDOF4+1]+macayeal_values[i*NDOF2+1];
     3938                vzstokes[i]=stokes_values[i*NDOF4+2];
     3939                pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
     3940        }
     3941
     3942        /*Get Vz*/
     3943        Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
     3944        if (vzmacayeal_input){
     3945                if (vzmacayeal_input->Enum()!=PentaVertexInputEnum){
     3946                        ISSMERROR("Cannot compute Vel as VzMacAyeal is of type %s",EnumToString(vzmacayeal_input->Enum()));
     3947                }
     3948                vzmacayeal_input->GetValuesPtr(&vzmacayeal_ptr,&dummy);
     3949                for(i=0;i<NUMVERTICES;i++) vzmacayeal[i]=vzmacayeal_ptr[i];
     3950        }
     3951        else{
     3952                ISSMERROR("Cannot update solution as VzMacAyeal is not present");
     3953        }
     3954
     3955        /*Now Compute vel*/
     3956        for(i=0;i<NUMVERTICES;i++) {
     3957                vz[i]=vzmacayeal[i]+vzstokes[i];
     3958                vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     3959        }
     3960
     3961        /*Now, we have to move the previous Vx and Vy inputs  to old
     3962         * status, otherwise, we'll wipe them off: */
     3963        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     3964        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     3965        this->inputs->ChangeEnum(VzEnum,VzOldEnum);
     3966        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     3967
     3968        /*Add vx and vy as inputs to the tria element: */
     3969        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     3970        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     3971        this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
     3972        this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
     3973        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     3974        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     3975
     3976        /*Free ressources:*/
     3977        xfree((void**)&doflistm);
     3978        xfree((void**)&doflists);
     3979}
     3980/*}}}*/
     3981/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattyn {{{1*/
     3982void  Penta::InputUpdateFromSolutionDiagnosticPattyn(double* solution){
     3983       
     3984        const int    numdof=NDOF2*NUMVERTICES;
     3985
     3986        int    i,dummy;
     3987        double rho_ice,g;
     3988        double values[numdof];
     3989        double vx[NUMVERTICES];
     3990        double vy[NUMVERTICES];
     3991        double vz[NUMVERTICES];
     3992        double vel[NUMVERTICES];
     3993        double pressure[NUMVERTICES];
     3994        double surface[NUMVERTICES];
     3995        double xyz_list[NUMVERTICES][3];
     3996        int*   doflist = NULL;
     3997        double *vz_ptr = NULL;
     3998
     3999        /*Get dof list: */
     4000        GetDofList(&doflist,PattynApproximationEnum,GsetEnum);
     4001
     4002        /*Get node data: */
     4003        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4004
     4005        /*Use the dof list to index into the solution vector: */
     4006        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4007
     4008        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4009        for(i=0;i<NUMVERTICES;i++){
     4010                vx[i]=values[i*NDOF2+0];
     4011                vy[i]=values[i*NDOF2+1];
     4012        }
     4013
     4014        /*Get Vz*/
     4015        Input* vz_input=inputs->GetInput(VzEnum);
     4016        if (vz_input){
     4017                if (vz_input->Enum()!=PentaVertexInputEnum){
     4018                        ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
     4019                }
     4020                vz_input->GetValuesPtr(&vz_ptr,&dummy);
     4021                for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
     4022        }
     4023        else{
     4024                for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
     4025        }
     4026
     4027        /*Now Compute vel*/
     4028        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     4029
     4030        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
     4031         *so the pressure is just the pressure at the z elevation: */
     4032        rho_ice=matpar->GetRhoIce();
     4033        g=matpar->GetG();
     4034        GetParameterListOnVertices(&surface[0],SurfaceEnum);
     4035        for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
     4036
     4037        /*Now, we have to move the previous Vx and Vy inputs  to old
     4038         * status, otherwise, we'll wipe them off: */
     4039        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     4040        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     4041        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     4042
     4043        /*Add vx and vy as inputs to the tria element: */
     4044        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     4045        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     4046        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     4047        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     4048
     4049        /*Free ressources:*/
     4050        xfree((void**)&doflist);
     4051}
     4052/*}}}*/
     4053/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattynStokes {{{1*/
     4054void  Penta::InputUpdateFromSolutionDiagnosticPattynStokes(double* solution){
     4055
     4056        const int    numdofp=NDOF2*NUMVERTICES;
     4057        const int    numdofs=NDOF4*NUMVERTICES;
     4058
     4059        int    i,dummy;
     4060        double pattyn_values[numdofp];
     4061        double stokes_values[numdofs];
     4062        double vx[NUMVERTICES];
     4063        double vy[NUMVERTICES];
     4064        double vz[NUMVERTICES];
     4065        double vzpattyn[NUMVERTICES];
     4066        double vzstokes[NUMVERTICES];
     4067        double vel[NUMVERTICES];
     4068        double pressure[NUMVERTICES];
     4069        double xyz_list[NUMVERTICES][3];
     4070        double stokesreconditioning;
     4071        int*   doflistp      = NULL;
     4072        int*   doflists      = NULL;
     4073        double *vzpattyn_ptr = NULL;
     4074        Penta  *penta        = NULL;
     4075
     4076        /*OK, we have to add results of this element for pattyn
     4077         * and results from the penta at base for macayeal. Now recover results*/
     4078        penta=GetBasalElement();
     4079
     4080        /*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
     4081        GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
     4082        GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
     4083        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     4084
     4085        /*Get node data: */
     4086        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4087
     4088        /*Use the dof list to index into the solution vector: */
     4089        for(i=0;i<numdofp;i++) pattyn_values[i]=solution[doflistp[i]];
     4090        for(i=0;i<numdofs;i++) stokes_values[i]=solution[doflists[i]];
     4091
     4092        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4093        for(i=0;i<NUMVERTICES;i++){
     4094                vx[i]=stokes_values[i*NDOF4+0]+pattyn_values[i*NDOF2+0];
     4095                vy[i]=stokes_values[i*NDOF4+1]+pattyn_values[i*NDOF2+1];
     4096                vzstokes[i]=stokes_values[i*NDOF4+2];
     4097                pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
     4098        }
     4099
     4100        /*Get Vz*/
     4101        Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
     4102        if (vzpattyn_input){
     4103                if (vzpattyn_input->Enum()!=PentaVertexInputEnum){
     4104                        ISSMERROR("Cannot compute Vel as VzPattyn is of type %s",EnumToString(vzpattyn_input->Enum()));
     4105                }
     4106                vzpattyn_input->GetValuesPtr(&vzpattyn_ptr,&dummy);
     4107                for(i=0;i<NUMVERTICES;i++) vzpattyn[i]=vzpattyn_ptr[i];
     4108        }
     4109        else{
     4110                ISSMERROR("Cannot update solution as VzPattyn is not present");
     4111        }
     4112
     4113        /*Now Compute vel*/
     4114        for(i=0;i<NUMVERTICES;i++) {
     4115                vz[i]=vzpattyn[i]+vzstokes[i];
     4116                vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     4117        }
     4118
     4119        /*Now, we have to move the previous Vx and Vy inputs  to old
     4120         * status, otherwise, we'll wipe them off: */
     4121        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     4122        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     4123        this->inputs->ChangeEnum(VzEnum,VzOldEnum);
     4124        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     4125
     4126        /*Add vx and vy as inputs to the tria element: */
     4127        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     4128        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     4129        this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
     4130        this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
     4131        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     4132        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     4133
     4134        /*Free ressources:*/
     4135        xfree((void**)&doflistp);
     4136        xfree((void**)&doflists);
     4137}
     4138/*}}}*/
     4139/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHutter {{{1*/
     4140void  Penta::InputUpdateFromSolutionDiagnosticHutter(double* solution){
     4141       
     4142        const int    numdof=NDOF2*NUMVERTICES;
     4143
     4144        int     i,dummy;
     4145        double  rho_ice,g;
     4146        double  values[numdof];
     4147        double  vx[NUMVERTICES];
     4148        double  vy[NUMVERTICES];
     4149        double  vz[NUMVERTICES];
     4150        double  vel[NUMVERTICES];
     4151        double  pressure[NUMVERTICES];
     4152        double  surface[NUMVERTICES];
     4153        double  xyz_list[NUMVERTICES][3];
     4154        int*    doflist = NULL;
     4155        double* vz_ptr  = NULL;
     4156
     4157        /*Get dof list: */
     4158        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4159
     4160        /*Get node data: */
     4161        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4162
     4163        /*Use the dof list to index into the solution vector: */
     4164        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4165
     4166        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4167        for(i=0;i<NUMVERTICES;i++){
     4168                vx[i]=values[i*NDOF2+0];
     4169                vy[i]=values[i*NDOF2+1];
     4170        }
     4171
     4172        /*Get Vz*/
     4173        Input* vz_input=inputs->GetInput(VzEnum);
     4174        if (vz_input){
     4175                if (vz_input->Enum()!=PentaVertexInputEnum){
     4176                        ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
     4177                }
     4178                vz_input->GetValuesPtr(&vz_ptr,&dummy);
     4179                for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
     4180        }
     4181        else{
     4182                for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
     4183        }
     4184
     4185        /*Now Compute vel*/
     4186        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     4187
     4188        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
     4189         *so the pressure is just the pressure at the z elevation: */
     4190        rho_ice=matpar->GetRhoIce();
     4191        g=matpar->GetG();
     4192        GetParameterListOnVertices(&surface[0],SurfaceEnum);
     4193        for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
     4194
     4195        /*Now, we have to move the previous Vx and Vy inputs  to old
     4196         * status, otherwise, we'll wipe them off: */
     4197        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     4198        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     4199        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     4200
     4201        /*Add vx and vy as inputs to the tria element: */
     4202        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     4203        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     4204        this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
     4205        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     4206
     4207        /*Free ressources:*/
     4208        xfree((void**)&doflist);
     4209}
     4210/*}}}*/
     4211/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticVert {{{1*/
     4212void  Penta::InputUpdateFromSolutionDiagnosticVert(double* solution){
     4213
     4214        const int numdof=NDOF1*NUMVERTICES;
     4215       
     4216        int      i,dummy;
     4217        int      approximation;
     4218        double   rho_ice,g;
     4219        double   values[numdof];
     4220        double   vx[NUMVERTICES];
     4221        double   vy[NUMVERTICES];
     4222        double   vz[NUMVERTICES];
     4223        double   vzmacayeal[NUMVERTICES];
     4224        double   vzpattyn[NUMVERTICES];
     4225        double   vzstokes[NUMVERTICES];
     4226        double   vel[NUMVERTICES];
     4227        double   pressure[NUMVERTICES];
     4228        double   surface[NUMVERTICES];
     4229        double   xyz_list[NUMVERTICES][3];
     4230        int*     doflist      = NULL;
     4231        double*  vx_ptr       = NULL;
     4232        double*  vy_ptr       = NULL;
     4233        double*  vzstokes_ptr = NULL;
     4234
     4235
     4236        /*Get the approximation and do nothing if the element in Stokes or None*/
     4237        inputs->GetParameterValue(&approximation,ApproximationEnum);
     4238        if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
     4239                return;
     4240        }
     4241
     4242        /*Get dof list and vertices coordinates: */
     4243        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4244        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4245
     4246        /*Use the dof list to index into the solution vector vz: */
     4247        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4248        for(i=0;i<NUMVERTICES;i++) vz[i]=values[i*NDOF1+0];
     4249
     4250        /*Get Vx and Vy*/
     4251        Input* vx_input=inputs->GetInput(VxEnum);
     4252        if (vx_input){
     4253                if (vx_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vx is of type %s",EnumToString(vx_input->Enum()));
     4254                vx_input->GetValuesPtr(&vx_ptr,&dummy);
     4255                for(i=0;i<NUMVERTICES;i++) vx[i]=vx_ptr[i];
     4256        }
     4257        else for(i=0;i<NUMVERTICES;i++) vx[i]=0.0;
     4258
     4259        Input* vy_input=inputs->GetInput(VyEnum);
     4260        if (vy_input){
     4261                if (vy_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vy is of type %s",EnumToString(vy_input->Enum()));
     4262                vy_input->GetValuesPtr(&vy_ptr,&dummy);
     4263                for(i=0;i<NUMVERTICES;i++) vy[i]=vy_ptr[i];
     4264        }
     4265        else for(i=0;i<NUMVERTICES;i++) vy[i]=0.0;
     4266
     4267        /*Do some modifications if we actually have a PattynStokes or MacAyealStokes element*/
     4268        if(approximation==PattynStokesApproximationEnum){
     4269                Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
     4270                if (vzstokes_input){
     4271                        if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
     4272                        vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
     4273                        for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
     4274                }
     4275                else ISSMERROR("Cannot compute Vz as VzStokes in not present in PattynStokes element");
     4276                for(i=0;i<NUMVERTICES;i++){
     4277                        vzpattyn[i]=vz[i];
     4278                        vz[i]=vzpattyn[i]+vzstokes[i];
     4279                }
     4280        }
     4281        else if(approximation==MacAyealStokesApproximationEnum){
     4282                Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
     4283                if (vzstokes_input){
     4284                        if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
     4285                        vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
     4286                        for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
     4287                }
     4288                else ISSMERROR("Cannot compute Vz as VzStokes in not present in MacAyealStokes element");
     4289                for(i=0;i<NUMVERTICES;i++){
     4290                        vzmacayeal[i]=vz[i];
     4291                        vz[i]=vzmacayeal[i]+vzstokes[i];
     4292                }
     4293        }
     4294
     4295        /*Now Compute vel*/
     4296        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     4297
     4298        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
     4299         *so the pressure is just the pressure at the z elevation: except it this is a PattynStokes element */
     4300        if(approximation!=PattynStokesApproximationEnum &&  approximation!=MacAyealStokesApproximationEnum){
     4301                rho_ice=matpar->GetRhoIce();
     4302                g=matpar->GetG();
     4303                GetParameterListOnVertices(&surface[0],SurfaceEnum);
     4304                for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
     4305        }
     4306
     4307        /*Now, we have to move the previous Vz inputs to old
     4308         * status, otherwise, we'll wipe them off and add the new inputs: */
     4309        this->inputs->ChangeEnum(VzEnum,VzOldEnum);
     4310
     4311        if(approximation!=PattynStokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum){
     4312                this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     4313                this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     4314        }
     4315        else if(approximation==PattynStokesApproximationEnum){
     4316                this->inputs->AddInput(new PentaVertexInput(VzPattynEnum,vzpattyn));
     4317        }
     4318        else if(approximation==MacAyealStokesApproximationEnum){
     4319                this->inputs->AddInput(new PentaVertexInput(VzMacAyealEnum,vzpattyn));
     4320        }
     4321
     4322        this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
     4323        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     4324
     4325        /*Free ressources:*/
     4326        xfree((void**)&doflist);
     4327}
     4328/*}}}*/
     4329/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticStokes {{{1*/
     4330void  Penta::InputUpdateFromSolutionDiagnosticStokes(double* solution){
     4331       
     4332        const int numdof=NDOF4*NUMVERTICES;
     4333
     4334        int     i;
     4335        double  values[numdof];
     4336        double  vx[NUMVERTICES];
     4337        double  vy[NUMVERTICES];
     4338        double  vz[NUMVERTICES];
     4339        double  vel[NUMVERTICES];
     4340        double  pressure[NUMVERTICES];
     4341        double  stokesreconditioning;
     4342        int*    doflist=NULL;
     4343
     4344        /*Get dof list: */
     4345        GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
     4346
     4347        /*Use the dof list to index into the solution vector: */
     4348        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4349
     4350        /*Ok, we have vx and vy in values, fill in all arrays: */
     4351        for(i=0;i<NUMVERTICES;i++){
     4352                vx[i]=values[i*NDOF4+0];
     4353                vy[i]=values[i*NDOF4+1];
     4354                vz[i]=values[i*NDOF4+2];
     4355                pressure[i]=values[i*NDOF4+3];
     4356        }
     4357
     4358        /*Recondition pressure and compute vel: */
     4359        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     4360        for(i=0;i<NUMVERTICES;i++) pressure[i]=pressure[i]*stokesreconditioning;
     4361        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     4362       
     4363        /*Now, we have to move the previous inputs  to old
     4364         * status, otherwise, we'll wipe them off: */
     4365        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     4366        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     4367        this->inputs->ChangeEnum(VzEnum,VzOldEnum);
     4368        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     4369
     4370        /*Add vx and vy as inputs to the tria element: */
     4371        this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
     4372        this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
     4373        this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
     4374        this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
     4375        this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
     4376
     4377        /*Free ressources:*/
     4378        xfree((void**)&doflist);
     4379}
     4380/*}}}*/
     4381/*FUNCTION Penta::InputUpdateFromSolutionAdjointStokes {{{1*/
     4382void  Penta::InputUpdateFromSolutionAdjointStokes(double* solution){
     4383
     4384        const int    numdof=NDOF4*NUMVERTICES;
     4385
     4386        int    i;
     4387        double values[numdof];
     4388        double lambdax[NUMVERTICES];
     4389        double lambday[NUMVERTICES];
     4390        double lambdaz[NUMVERTICES];
     4391        double lambdap[NUMVERTICES];
     4392        int*   doflist=NULL;
     4393
     4394        /*Get dof list: */
     4395        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4396
     4397        /*Use the dof list to index into the solution vector: */
     4398        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4399
     4400        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4401        for(i=0;i<NUMVERTICES;i++){
     4402                lambdax[i]=values[i*NDOF4+0];
     4403                lambday[i]=values[i*NDOF4+1];
     4404                lambdaz[i]=values[i*NDOF4+2];
     4405                lambdap[i]=values[i*NDOF4+3];
     4406        }
     4407
     4408        /*Add vx and vy as inputs to the tria element: */
     4409        this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
     4410        this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
     4411        this->inputs->AddInput(new PentaVertexInput(AdjointzEnum,lambdaz));
     4412        this->inputs->AddInput(new PentaVertexInput(AdjointpEnum,lambdap));
     4413
     4414        /*Free ressources:*/
     4415        xfree((void**)&doflist);
     4416}
     4417/*}}}*/
     4418/*FUNCTION Penta::InputUpdateFromSolutionAdjointHoriz {{{1*/
     4419void  Penta::InputUpdateFromSolutionAdjointHoriz(double* solution){
     4420
     4421        const int numdof=NDOF2*NUMVERTICES;
     4422
     4423        int    i;
     4424        double values[numdof];
     4425        double lambdax[NUMVERTICES];
     4426        double lambday[NUMVERTICES];
     4427        int*   doflist=NULL;
     4428
     4429        /*Get dof list: */
     4430        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4431
     4432        /*Use the dof list to index into the solution vector: */
     4433        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4434
     4435        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4436        for(i=0;i<NUMVERTICES;i++){
     4437                lambdax[i]=values[i*NDOF2+0];
     4438                lambday[i]=values[i*NDOF2+1];
     4439        }
     4440
     4441        /*Add vx and vy as inputs to the tria element: */
     4442        this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
     4443        this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
     4444
     4445        /*Free ressources:*/
     4446        xfree((void**)&doflist);
     4447}
     4448/*}}}*/
     4449/*FUNCTION Penta::InputUpdateFromSolutionThermal {{{1*/
     4450void  Penta::InputUpdateFromSolutionThermal(double* solution){
     4451
     4452        const int    numdof=NDOF1*NUMVERTICES;
     4453
     4454        bool   converged;
     4455        int    i;
     4456        double values[numdof];
     4457        double B[numdof];
     4458        double B_average;
     4459        int*   doflist=NULL;
     4460
     4461        /*Get dof list: */
     4462        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4463
     4464        /*Use the dof list to index into the solution vector: */
     4465        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4466
     4467        this->inputs->GetParameterValue(&converged,ConvergedEnum);
     4468        if(converged){
     4469                this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,values));
     4470
     4471                /*Update Rheology only if convreged (we must make sure that the temperature is below melting point
     4472                 * otherwise the rheology could be negative*/
     4473                B_average=Paterson((values[0]+values[1]+values[2]+values[3]+values[4]+values[5])/6.0);
     4474                for(i=0;i<numdof;i++) B[i]=B_average;
     4475                this->matice->inputs->AddInput(new PentaVertexInput(RheologyBEnum,B));
     4476        }
     4477        else{
     4478                this->inputs->AddInput(new PentaVertexInput(TemporaryTemperatureEnum,values));
     4479        }
     4480
     4481        /*Free ressources:*/
     4482        xfree((void**)&doflist);
     4483}
     4484/*}}}*/
     4485/*FUNCTION Penta::InputUpdateFromSolutionOneDof{{{1*/
     4486void  Penta::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
     4487
     4488        const int numdof = NDOF1*NUMVERTICES;
     4489
     4490        double values[numdof];
     4491        int*   doflist=NULL;
     4492
     4493        /*Get dof list: */
     4494        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4495
     4496        /*Use the dof list to index into the solution vector: */
     4497        for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     4498
     4499        /*Add input to the element: */
     4500        this->inputs->AddInput(new PentaVertexInput(enum_type,values));
     4501       
     4502        /*Free ressources:*/
     4503        xfree((void**)&doflist);
     4504}
     4505/*}}}*/
     4506/*FUNCTION Penta::InputUpdateFromSolutionOneDofCollpased{{{1*/
     4507void  Penta::InputUpdateFromSolutionOneDofCollapsed(double* solution,int enum_type){
     4508
     4509        const int  numdof   = NDOF1*NUMVERTICES;
     4510        const int  numdof2d = NDOF1*NUMVERTICES2D;
     4511
     4512        double  values[numdof];
     4513        int*    doflist = NULL;
     4514        Penta  *penta   = NULL;
     4515
     4516        /*If not on bed, return*/
     4517        if (!IsOnBed()) return;
     4518
     4519        /*Get dof list: */
     4520        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     4521
     4522        /*Use the dof list to index into the solution vector and extrude it */
     4523        for(int i=0;i<numdof2d;i++){
     4524                values[i]         =solution[doflist[i]];
     4525                values[i+numdof2d]=values[i];
     4526        }
     4527
     4528        /*Start looping over all elements above current element and update all inputs*/
     4529        penta=this;
     4530        for(;;){
     4531                /*Add input to the element: */
     4532                penta->inputs->AddInput(new PentaVertexInput(enum_type,values));
     4533
     4534                /*Stop if we have reached the surface*/
     4535                if (penta->IsOnSurface()) break;
     4536
     4537                /* get upper Penta*/
     4538                penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
     4539        }
     4540       
     4541        /*Free ressources:*/
     4542        xfree((void**)&doflist);
     4543}
     4544/*}}}*/
     4545/*FUNCTION Penta::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
     4546void  Penta::InputUpdateFromVector(double* vector, int name, int type){
     4547
     4548        /*Check that name is an element input*/
     4549        if (!IsInput(name)) return;
     4550
     4551        /*Penta update B in InputUpdateFromSolutionThermal, so don't look for B update here.*/
     4552
     4553        switch(type){
     4554
     4555                case VertexEnum:
     4556
     4557                        /*New PentaVertexInpu*/
     4558                        double values[6];
     4559
     4560                        /*Get values on the 6 vertices*/
     4561                        for (int i=0;i<6;i++){
     4562                                values[i]=vector[this->nodes[i]->GetVertexDof()];
     4563                        }
     4564
     4565                        /*update input*/
     4566                        this->inputs->AddInput(new PentaVertexInput(name,values));
     4567                        return;
     4568
     4569                default:
     4570
     4571                        ISSMERROR("type %i (%s) not implemented yet",type,EnumToString(type));
     4572        }
     4573}
     4574/*}}}*/
     4575/*FUNCTION Penta::InputUpdateFromVector(int* vector, int name, int type);{{{1*/
     4576void  Penta::InputUpdateFromVector(int* vector, int name, int type){
     4577        ISSMERROR(" not supported yet!");
     4578}
     4579/*}}}*/
     4580/*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{1*/
     4581void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
     4582        ISSMERROR(" not supported yet!");
     4583}
     4584/*}}}*/
     4585/*FUNCTION Penta::InputUpdateFromVectorDakota(double* vector, int name, int type);{{{1*/
     4586void  Penta::InputUpdateFromVectorDakota(double* vector, int name, int type){
     4587        ISSMERROR(" not supported yet!");
     4588}
     4589/*}}}*/
     4590/*FUNCTION Penta::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{1*/
     4591void  Penta::InputUpdateFromVectorDakota(int* vector, int name, int type){
     4592        ISSMERROR(" not supported yet!");
     4593}
     4594/*}}}*/
     4595/*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{1*/
     4596void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
     4597        ISSMERROR(" not supported yet!");
     4598}
     4599/*}}}*/
     4600/*FUNCTION Penta::IsOnBed{{{1*/
     4601bool Penta::IsOnBed(void){
     4602
     4603        bool onbed;
     4604        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     4605        return onbed;
     4606}
     4607/*}}}*/
     4608/*FUNCTION Penta::IsInput{{{1*/
     4609bool Penta::IsInput(int name){
     4610        if (
     4611                                name==ThicknessEnum ||
     4612                                name==SurfaceEnum ||
     4613                                name==BedEnum ||
     4614                                name==DtEnum ||
     4615                                name==SurfaceSlopeXEnum ||
     4616                                name==SurfaceSlopeYEnum ||
     4617                                name==MeltingRateEnum ||
     4618                                name==AccumulationRateEnum ||
     4619                                name==GeothermalFluxEnum ||
     4620                                name==SurfaceAreaEnum||
     4621                                name==PressureEnum ||
     4622                                name==VxEnum ||
     4623                                name==VyEnum ||
     4624                                name==VzEnum ||
     4625                                name==VxObsEnum ||
     4626                                name==VyObsEnum ||
     4627                                name==VzObsEnum ||
     4628                                name==TemperatureEnum ||
     4629                                name==CmResponseEnum ||
     4630                                name==DragCoefficientEnum ||
     4631                                name==GradientEnum ||
     4632                                name==OldGradientEnum  ||
     4633                                name==ConvergedEnum
     4634                                ) {
     4635                return true;
     4636        }
     4637        else return false;
     4638}
     4639/*}}}*/
     4640/*FUNCTION Penta::IsOnShelf {{{1*/
     4641bool   Penta::IsOnShelf(){
     4642
     4643        bool onshelf;
     4644        inputs->GetParameterValue(&onshelf,ElementOnIceShelfEnum);
     4645        return onshelf;
     4646}
     4647/*}}}*/
     4648/*FUNCTION Penta::IsOnSurface{{{1*/
     4649bool Penta::IsOnSurface(void){
     4650
     4651        bool onsurface;
     4652        inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
     4653        return onsurface;
     4654}
     4655/*}}}*/
     4656/*FUNCTION Penta::IsOnWater {{{1*/
     4657bool   Penta::IsOnWater(){
     4658
     4659        bool onwater;
     4660        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     4661        return onwater;
     4662}
     4663/*}}}*/
    13184664/*FUNCTION Penta::MassFlux {{{1*/
    13194665double Penta::MassFlux( double* segment,bool process_units){
     
    14134759}
    14144760/*}}}*/
     4761/*FUNCTION Penta::MinEdgeLength{{{1*/
     4762double Penta::MinEdgeLength(double xyz_list[6][3]){
     4763        /*Return the minimum lenght of the nine egdes of the penta*/
     4764
     4765        int    i,node0,node1;
     4766        int    edges[9][2]={{0,1},{0,2},{1,2},{3,4},{3,5},{4,5},{0,3},{1,4},{2,5}}; //list of the nine edges
     4767        double length;
     4768        double minlength=-1;
     4769
     4770        for(i=0;i<9;i++){
     4771                /*Find the two nodes for this edge*/
     4772                node0=edges[i][0];
     4773                node1=edges[i][1];
     4774
     4775                /*Compute the length of this edge and compare it to the minimal length*/
     4776                length=pow(pow(xyz_list[node0][0]-xyz_list[node1][0],2.0)+pow(xyz_list[node0][1]-xyz_list[node1][1],2.0)+pow(xyz_list[node0][2]-xyz_list[node1][2],2.0),0.5);
     4777                if(length<minlength || minlength<0) minlength=length;
     4778        }
     4779
     4780        return minlength;
     4781}
     4782/*}}}*/
    14154783/*FUNCTION Penta::MinVel{{{1*/
    14164784void  Penta::MinVel(double* pminvel, bool process_units){
     
    14634831        /*Assign output pointers:*/
    14644832        *pminvz=minvz;
     4833}
     4834/*}}}*/
     4835/*FUNCTION Penta::MyRank {{{1*/
     4836int    Penta::MyRank(void){
     4837        extern int my_rank;
     4838        return my_rank;
     4839}
     4840/*}}}*/
     4841/*FUNCTION Penta::PatchFill{{{1*/
     4842void  Penta::PatchFill(int* pcount, Patch* patch){
     4843
     4844        int i,count;
     4845        int vertices_ids[6];
     4846
     4847        /*recover pointer: */
     4848        count=*pcount;
     4849               
     4850        /*will be needed later: */
     4851        for(i=0;i<6;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
     4852
     4853        for(i=0;i<this->results->Size();i++){
     4854                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4855
     4856                /*For this result,fill the information in the Patch object (element id + vertices ids), and then hand
     4857                 *it to the result object, to fill the rest: */
     4858                patch->fillelementinfo(count,this->id,vertices_ids,6);
     4859                elementresult->PatchFill(count,patch);
     4860
     4861                /*increment counter: */
     4862                count++;
     4863        }
     4864
     4865        /*Assign output pointers:*/
     4866        *pcount=count;
     4867}/*}}}*/
     4868/*FUNCTION Penta::PatchSize{{{1*/
     4869void  Penta::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
     4870
     4871        int     i;
     4872        int     numrows  = 0;
     4873        int     numnodes = 0;
     4874
     4875        /*Go through all the results objects, and update the counters: */
     4876        for (i=0;i<this->results->Size();i++){
     4877                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4878                /*first, we have one more result: */
     4879                numrows++;
     4880                /*now, how many vertices and how many nodal values for this result? :*/
     4881                numnodes=elementresult->NumberOfNodalValues(); //ask result object.
     4882        }
     4883
     4884        /*Assign output pointers:*/
     4885        *pnumrows=numrows;
     4886        *pnumvertices=NUMVERTICES;
     4887        *pnumnodes=numnodes;
     4888}
     4889/*}}}*/
     4890/*FUNCTION Penta::ProcessResultsUnits{{{1*/
     4891void  Penta::ProcessResultsUnits(void){
     4892
     4893        int i;
     4894
     4895        for(i=0;i<this->results->Size();i++){
     4896                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4897                elementresult->ProcessUnits(this->parameters);
     4898        }
     4899}
     4900/*}}}*/
     4901/*FUNCTION Penta::ReduceMatrixStokes {{{1*/
     4902void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
     4903
     4904        int    i,j;
     4905        double Kii[24][24];
     4906        double Kib[24][3];
     4907        double Kbb[3][3];
     4908        double Kbi[3][24];
     4909        double Kbbinv[3][3];
     4910        double Kright[24][24];
     4911
     4912        /*Create the four matrices used for reduction */
     4913        for(i=0;i<24;i++){
     4914                for(j=0;j<24;j++){
     4915                        Kii[i][j]=*(Ke_temp+27*i+j);
     4916                }
     4917                for(j=0;j<3;j++){
     4918                        Kib[i][j]=*(Ke_temp+27*i+j+24);
     4919                }
     4920        }
     4921        for(i=0;i<3;i++){
     4922                for(j=0;j<24;j++){
     4923                        Kbi[i][j]=*(Ke_temp+27*(i+24)+j);
     4924                }
     4925                for(j=0;j<3;j++){
     4926                        Kbb[i][j]=*(Ke_temp+27*(i+24)+j+24);
     4927                }
     4928        }
     4929
     4930        /*Inverse the matrix corresponding to bubble part Kbb */
     4931        Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
     4932
     4933        /*Multiply matrices to create the reduce matrix Ke_reduced */
     4934        TripleMultiply(&Kib[0][0],24,3,0,
     4935                                &Kbbinv[0][0],3,3,0,
     4936                                &Kbi[0][0],3,24,0,
     4937                                &Kright[0][0],0);
     4938
     4939        /*Affect value to the reduced matrix */
     4940        for(i=0;i<24;i++) for(j=0;j<24;j++) *(Ke_reduced+24*i+j)=Kii[i][j]-Kright[i][j];
     4941}
     4942/*}}}*/
     4943/*FUNCTION Penta::ReduceVectorStokes {{{1*/
     4944void Penta::ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp){
     4945
     4946        int    i,j;
     4947        double Pi[24];
     4948        double Pb[3];
     4949        double Kbb[3][3];
     4950        double Kib[24][3];
     4951        double Kbbinv[3][3];
     4952        double Pright[24];
     4953
     4954        /*Create the four matrices used for reduction */
     4955        for(i=0;i<24;i++) Pi[i]=*(Pe_temp+i);
     4956        for(i=0;i<3;i++) Pb[i]=*(Pe_temp+i+24);
     4957        for(j=0;j<3;j++){
     4958                for(i=0;i<24;i++){
     4959                        Kib[i][j]=*(Ke_temp+3*i+j);
     4960                }
     4961                for(i=0;i<3;i++){
     4962                        Kbb[i][j]=*(Ke_temp+3*(i+24)+j);
     4963                }
     4964        }
     4965
     4966        /*Inverse the matrix corresponding to bubble part Kbb */
     4967        Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
     4968
     4969        /*Multiply matrices to create the reduce matrix Ke_reduced */
     4970        TripleMultiply(&Kib[0][0],24,3,0,
     4971                                &Kbbinv[0][0],3,3,0,
     4972                                &Pb[0],3,1,0,&Pright[0],0);
     4973
     4974        /*Affect value to the reduced matrix */
     4975        for(i=0;i<24;i++) *(Pe_reduced+i)=Pi[i]-Pright[i];
     4976}
     4977/*}}}*/
     4978/*FUNCTION Penta::RegularizeInversion {{{1*/
     4979double Penta::RegularizeInversion(void){
     4980
     4981        double J;
     4982        Tria* tria=NULL;
     4983
     4984        /*recover some inputs: */
     4985        int  approximation;
     4986        inputs->GetParameterValue(&approximation,ApproximationEnum);
     4987
     4988        /*If on water, return 0: */
     4989        if(IsOnWater())return 0;
     4990
     4991        /*Bail out if this element if:
     4992         * -> Not MacAyeal and not on the surface
     4993         * -> MacAyeal (2d model) and not on bed) */
     4994        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     4995                return 0;
     4996        }
     4997        else if (approximation==MacAyealApproximationEnum){
     4998
     4999                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5000                 * and compute RegularizeInversion*/
     5001
     5002                /*Depth Average B*/
     5003                this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
     5004
     5005                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5006                J=tria->RegularizeInversion();
     5007                delete tria->matice; delete tria;
     5008
     5009                /*delete B average*/
     5010                this->matice->inputs->DeleteInput(RheologyBbarEnum);
     5011
     5012                return J;
     5013        }
     5014        else{
     5015
     5016                /*Depth Average B and put it in inputs*/
     5017                Penta* penta=GetBasalElement();
     5018                penta->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
     5019                Input* B_input=penta->matice->inputs->GetInput(RheologyBbarEnum);
     5020                Input* B_copy=(Input*)B_input->copy();
     5021                this->matice->inputs->AddInput((Input*)B_copy);
     5022
     5023                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5024                J=tria->RegularizeInversion();
     5025                delete tria->matice; delete tria;
     5026
     5027                /*delete B average*/
     5028                this->matice->inputs->DeleteInput(RheologyBbarEnum);
     5029                penta->matice->inputs->DeleteInput(RheologyBbarEnum);
     5030
     5031                return J;
     5032        }
     5033}
     5034/*}}}*/
     5035/*FUNCTION Penta::SetClone {{{1*/
     5036void  Penta::SetClone(int* minranks){
     5037
     5038        ISSMERROR("not implemented yet");
     5039}
     5040/*}}}1*/
     5041/*FUNCTION Penta::SetCurrentConfiguration {{{1*/
     5042void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
     5043
     5044        int analysis_counter;
     5045
     5046        /*go into parameters and get the analysis_counter: */
     5047        parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
     5048
     5049        /*Get Element type*/
     5050        this->element_type=this->element_type_list[analysis_counter];
     5051
     5052        /*Pick up nodes */
     5053        if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
     5054        else this->nodes=NULL;
     5055}
     5056/*}}}*/
     5057/*FUNCTION Penta::SpawnTria {{{1*/
     5058Tria*  Penta::SpawnTria(int g0, int g1, int g2){
     5059
     5060        int   i,analysis_counter;
     5061        int   indices[3];
     5062        int   zero=0;
     5063        Tria*       tria            = NULL;
     5064        Inputs*     tria_inputs     = NULL;
     5065        Results*    tria_results    = NULL;
     5066        Parameters* tria_parameters = NULL;
     5067
     5068        /*go into parameters and get the analysis_counter: */
     5069        this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
     5070
     5071        indices[0]=g0;
     5072        indices[1]=g1;
     5073        indices[2]=g2;
     5074
     5075        tria_parameters=this->parameters;
     5076        tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
     5077        tria_results=(Results*)this->results->SpawnTriaResults(indices);
     5078
     5079        tria=new Tria();
     5080        tria->id=this->id;
     5081        tria->inputs=tria_inputs;
     5082        tria->results=tria_results;
     5083        tria->parameters=tria_parameters;
     5084        tria->element_type=P1Enum; //Only P1 CG for now (TO BE CHANGED)
     5085        this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
     5086
     5087        /*Spawn matice*/
     5088        tria->matice=NULL;
     5089        tria->matice=(Matice*)this->matice->copy();
     5090        delete tria->matice->inputs;
     5091        tria->matice->inputs=(Inputs*)this->matice->inputs->SpawnTriaInputs(indices);
     5092
     5093        /*recover nodes, matice and matpar: */
     5094        tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
     5095        tria->matpar=(Matpar*)tria->hmatpar->delivers();
     5096
     5097        return tria;
     5098}
     5099/*}}}*/
     5100/*FUNCTION Penta::SurfaceArea {{{1*/
     5101double Penta::SurfaceArea(void){
     5102
     5103        int    approximation;
     5104        double S;
     5105        Tria*  tria=NULL;
     5106
     5107        /*retrieve inputs :*/
     5108        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5109
     5110        /*If on water, return 0: */
     5111        if(IsOnWater())return 0;
     5112
     5113        /*Bail out if this element if:
     5114         * -> Non MacAyeal not on the surface
     5115         * -> MacAyeal (2d model) and not on bed) */
     5116        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5117                return 0;
     5118        }
     5119        else if (approximation==MacAyealApproximationEnum){
     5120
     5121                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5122                 * and compute SurfaceArea*/
     5123                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5124                S=tria->SurfaceArea();
     5125                delete tria->matice; delete tria;
     5126                return S;
     5127        }
     5128        else{
     5129
     5130                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5131                S=tria->SurfaceArea();
     5132                delete tria->matice; delete tria;
     5133                return S;
     5134        }
     5135}
     5136/*}}}*/
     5137/*FUNCTION Penta::SurfaceAverageVelMisfit {{{1*/
     5138double Penta::SurfaceAverageVelMisfit(bool process_units){
     5139
     5140        int    approximation;
     5141        double J;
     5142        Tria*  tria=NULL;
     5143
     5144        /*retrieve inputs :*/
     5145        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5146
     5147        /*If on water, return 0: */
     5148        if(IsOnWater())return 0;
     5149
     5150        /*Bail out if this element if:
     5151         * -> Non MacAyeal and not on the surface
     5152         * -> MacAyeal (2d model) and not on bed) */
     5153        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5154                return 0;
     5155        }
     5156        else if (approximation==MacAyealApproximationEnum){
     5157
     5158                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5159                 * and compute SurfaceAverageVelMisfit*/
     5160                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5161                J=tria->SurfaceAverageVelMisfit(process_units);
     5162                delete tria->matice; delete tria;
     5163                return J;
     5164        }
     5165        else{
     5166
     5167                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5168                J=tria->SurfaceAverageVelMisfit(process_units);
     5169                delete tria->matice; delete tria;
     5170                return J;
     5171        }
     5172}
     5173/*}}}*/
     5174/*FUNCTION Penta::SurfaceAbsVelMisfit {{{1*/
     5175double Penta::SurfaceAbsVelMisfit(bool process_units){
     5176
     5177        int    approximation;
     5178        double J;
     5179        Tria*  tria=NULL;
     5180
     5181        /*retrieve inputs :*/
     5182        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5183
     5184        /*If on water, return 0: */
     5185        if(IsOnWater())return 0;
     5186
     5187        /*Bail out if this element if:
     5188         * -> Non MacAyeal and not on the surface
     5189         * -> MacAyeal (2d model) and not on bed) */
     5190        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5191                return 0;
     5192        }
     5193        else if (approximation==MacAyealApproximationEnum){
     5194
     5195                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5196                 * and compute SurfaceAbsVelMisfit*/
     5197                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5198                J=tria->SurfaceAbsVelMisfit(process_units);
     5199                delete tria->matice; delete tria;
     5200                return J;
     5201        }
     5202        else{
     5203
     5204                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5205                J=tria->SurfaceAbsVelMisfit(process_units);
     5206                delete tria->matice; delete tria;
     5207                return J;
     5208        }
     5209}
     5210/*}}}*/
     5211/*FUNCTION Penta::SurfaceLogVelMisfit {{{1*/
     5212double Penta::SurfaceLogVelMisfit(bool process_units){
     5213
     5214        int    approximation;
     5215        double J;
     5216        Tria*  tria=NULL;
     5217
     5218        /*retrieve inputs :*/
     5219        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5220
     5221        /*If on water, return 0: */
     5222        if(IsOnWater())return 0;
     5223
     5224        /*Bail out if this element if:
     5225         * -> Non MacAyeal and not on the surface
     5226         * -> MacAyeal (2d model) and not on bed) */
     5227        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5228                return 0;
     5229        }
     5230        else if (approximation==MacAyealApproximationEnum){
     5231
     5232                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5233                 * and compute SurfaceLogVelMisfit*/
     5234                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5235                J=tria->SurfaceLogVelMisfit(process_units);
     5236                delete tria->matice; delete tria;
     5237                return J;
     5238        }
     5239        else{
     5240
     5241                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5242                J=tria->SurfaceLogVelMisfit(process_units);
     5243                delete tria->matice; delete tria;
     5244                return J;
     5245        }
     5246}
     5247/*}}}*/
     5248/*FUNCTION Penta::SurfaceLogVxVyMisfit {{{1*/
     5249double Penta::SurfaceLogVxVyMisfit(bool process_units){
     5250
     5251        double J;
     5252        Tria* tria=NULL;
     5253
     5254        /*inputs: */
     5255        int  approximation;
     5256
     5257        /*retrieve inputs :*/
     5258        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5259
     5260        /*If on water, return 0: */
     5261        if(IsOnWater())return 0;
     5262
     5263        /*Bail out if this element if:
     5264         * -> Non MacAyeal and not on the surface
     5265         * -> MacAyeal (2d model) and not on bed) */
     5266        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5267                return 0;
     5268        }
     5269        else if (approximation==MacAyealApproximationEnum){
     5270
     5271                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5272                 * and compute SurfaceLogVxVyMisfit*/
     5273                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5274                J=tria->SurfaceLogVxVyMisfit(process_units);
     5275                delete tria->matice; delete tria;
     5276                return J;
     5277        }
     5278        else{
     5279
     5280                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5281                J=tria->SurfaceLogVxVyMisfit(process_units);
     5282                delete tria->matice; delete tria;
     5283                return J;
     5284        }
     5285}
     5286/*}}}*/
     5287/*FUNCTION Penta::SurfaceNormal {{{1*/
     5288void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
     5289
     5290        int    i;
     5291        double v13[3],v23[3];
     5292        double normal[3];
     5293        double normal_norm;
     5294
     5295        for (i=0;i<3;i++){
     5296                v13[i]=xyz_list[0][i]-xyz_list[2][i];
     5297                v23[i]=xyz_list[1][i]-xyz_list[2][i];
     5298        }
     5299
     5300        normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
     5301        normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
     5302        normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
     5303
     5304        normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
     5305
     5306        *(surface_normal)=normal[0]/normal_norm;
     5307        *(surface_normal+1)=normal[1]/normal_norm;
     5308        *(surface_normal+2)=normal[2]/normal_norm;
     5309}
     5310/*}}}*/
     5311/*FUNCTION Penta::SurfaceRelVelMisfit {{{1*/
     5312double Penta::SurfaceRelVelMisfit(bool process_units){
     5313
     5314        int    approximation;
     5315        double J;
     5316        Tria*  tria=NULL;
     5317
     5318        /*retrieve inputs :*/
     5319        inputs->GetParameterValue(&approximation,ApproximationEnum);
     5320
     5321        /*If on water, return 0: */
     5322        if(IsOnWater())return 0;
     5323
     5324        /*Bail out if this element if:
     5325         * -> Non MacAyeal and not on the surface
     5326         * -> MacAyeal (2d model) and not on bed) */
     5327        if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
     5328                return 0;
     5329        }
     5330        else if (approximation==MacAyealApproximationEnum){
     5331
     5332                /*This element should be collapsed into a tria element at its base. Create this tria element,
     5333                 * and compute SurfaceRelVelMisfit*/
     5334                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     5335                J=tria->SurfaceRelVelMisfit(process_units);
     5336                delete tria->matice; delete tria;
     5337                return J;
     5338        }
     5339        else{
     5340
     5341                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     5342                J=tria->SurfaceRelVelMisfit(process_units);
     5343                delete tria->matice; delete tria;
     5344                return J;
     5345        }
    14655346}
    14665347/*}}}*/
     
    15275408        delete tria->matice; delete tria;
    15285409        return J;
    1529 }
    1530 /*}}}*/
    1531 /*FUNCTION Penta::SurfaceAbsVelMisfit {{{1*/
    1532 double Penta::SurfaceAbsVelMisfit(bool process_units){
    1533 
    1534         int    approximation;
    1535         double J;
    1536         Tria*  tria=NULL;
    1537 
    1538         /*retrieve inputs :*/
    1539         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1540 
    1541         /*If on water, return 0: */
    1542         if(IsOnWater())return 0;
    1543 
    1544         /*Bail out if this element if:
    1545          * -> Non MacAyeal and not on the surface
    1546          * -> MacAyeal (2d model) and not on bed) */
    1547         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1548                 return 0;
    1549         }
    1550         else if (approximation==MacAyealApproximationEnum){
    1551 
    1552                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1553                  * and compute SurfaceAbsVelMisfit*/
    1554                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1555                 J=tria->SurfaceAbsVelMisfit(process_units);
    1556                 delete tria->matice; delete tria;
    1557                 return J;
    1558         }
    1559         else{
    1560 
    1561                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1562                 J=tria->SurfaceAbsVelMisfit(process_units);
    1563                 delete tria->matice; delete tria;
    1564                 return J;
    1565         }
    1566 }
    1567 /*}}}*/
    1568 /*FUNCTION Penta::SurfaceRelVelMisfit {{{1*/
    1569 double Penta::SurfaceRelVelMisfit(bool process_units){
    1570 
    1571         int    approximation;
    1572         double J;
    1573         Tria*  tria=NULL;
    1574 
    1575         /*retrieve inputs :*/
    1576         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1577 
    1578         /*If on water, return 0: */
    1579         if(IsOnWater())return 0;
    1580 
    1581         /*Bail out if this element if:
    1582          * -> Non MacAyeal and not on the surface
    1583          * -> MacAyeal (2d model) and not on bed) */
    1584         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1585                 return 0;
    1586         }
    1587         else if (approximation==MacAyealApproximationEnum){
    1588 
    1589                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1590                  * and compute SurfaceRelVelMisfit*/
    1591                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1592                 J=tria->SurfaceRelVelMisfit(process_units);
    1593                 delete tria->matice; delete tria;
    1594                 return J;
    1595         }
    1596         else{
    1597 
    1598                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1599                 J=tria->SurfaceRelVelMisfit(process_units);
    1600                 delete tria->matice; delete tria;
    1601                 return J;
    1602         }
    1603 }
    1604 /*}}}*/
    1605 /*FUNCTION Penta::SurfaceLogVelMisfit {{{1*/
    1606 double Penta::SurfaceLogVelMisfit(bool process_units){
    1607 
    1608         int    approximation;
    1609         double J;
    1610         Tria*  tria=NULL;
    1611 
    1612         /*retrieve inputs :*/
    1613         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1614 
    1615         /*If on water, return 0: */
    1616         if(IsOnWater())return 0;
    1617 
    1618         /*Bail out if this element if:
    1619          * -> Non MacAyeal and not on the surface
    1620          * -> MacAyeal (2d model) and not on bed) */
    1621         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1622                 return 0;
    1623         }
    1624         else if (approximation==MacAyealApproximationEnum){
    1625 
    1626                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1627                  * and compute SurfaceLogVelMisfit*/
    1628                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1629                 J=tria->SurfaceLogVelMisfit(process_units);
    1630                 delete tria->matice; delete tria;
    1631                 return J;
    1632         }
    1633         else{
    1634 
    1635                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1636                 J=tria->SurfaceLogVelMisfit(process_units);
    1637                 delete tria->matice; delete tria;
    1638                 return J;
    1639         }
    1640 }
    1641 /*}}}*/
    1642 /*FUNCTION Penta::SurfaceLogVxVyMisfit {{{1*/
    1643 double Penta::SurfaceLogVxVyMisfit(bool process_units){
    1644 
    1645         double J;
    1646         Tria* tria=NULL;
    1647 
    1648         /*inputs: */
    1649         int  approximation;
    1650 
    1651         /*retrieve inputs :*/
    1652         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1653 
    1654         /*If on water, return 0: */
    1655         if(IsOnWater())return 0;
    1656 
    1657         /*Bail out if this element if:
    1658          * -> Non MacAyeal and not on the surface
    1659          * -> MacAyeal (2d model) and not on bed) */
    1660         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1661                 return 0;
    1662         }
    1663         else if (approximation==MacAyealApproximationEnum){
    1664 
    1665                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1666                  * and compute SurfaceLogVxVyMisfit*/
    1667                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1668                 J=tria->SurfaceLogVxVyMisfit(process_units);
    1669                 delete tria->matice; delete tria;
    1670                 return J;
    1671         }
    1672         else{
    1673 
    1674                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1675                 J=tria->SurfaceLogVxVyMisfit(process_units);
    1676                 delete tria->matice; delete tria;
    1677                 return J;
    1678         }
    1679 }
    1680 /*}}}*/
    1681 /*FUNCTION Penta::SurfaceAverageVelMisfit {{{1*/
    1682 double Penta::SurfaceAverageVelMisfit(bool process_units){
    1683 
    1684         int    approximation;
    1685         double J;
    1686         Tria*  tria=NULL;
    1687 
    1688         /*retrieve inputs :*/
    1689         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1690 
    1691         /*If on water, return 0: */
    1692         if(IsOnWater())return 0;
    1693 
    1694         /*Bail out if this element if:
    1695          * -> Non MacAyeal and not on the surface
    1696          * -> MacAyeal (2d model) and not on bed) */
    1697         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1698                 return 0;
    1699         }
    1700         else if (approximation==MacAyealApproximationEnum){
    1701 
    1702                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1703                  * and compute SurfaceAverageVelMisfit*/
    1704                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1705                 J=tria->SurfaceAverageVelMisfit(process_units);
    1706                 delete tria->matice; delete tria;
    1707                 return J;
    1708         }
    1709         else{
    1710 
    1711                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1712                 J=tria->SurfaceAverageVelMisfit(process_units);
    1713                 delete tria->matice; delete tria;
    1714                 return J;
    1715         }
    1716 }
    1717 /*}}}*/
    1718 /*FUNCTION Penta::PatchFill{{{1*/
    1719 void  Penta::PatchFill(int* pcount, Patch* patch){
    1720 
    1721         int i,count;
    1722         int vertices_ids[6];
    1723 
    1724         /*recover pointer: */
    1725         count=*pcount;
    1726                
    1727         /*will be needed later: */
    1728         for(i=0;i<6;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
    1729 
    1730         for(i=0;i<this->results->Size();i++){
    1731                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    1732 
    1733                 /*For this result,fill the information in the Patch object (element id + vertices ids), and then hand
    1734                  *it to the result object, to fill the rest: */
    1735                 patch->fillelementinfo(count,this->id,vertices_ids,6);
    1736                 elementresult->PatchFill(count,patch);
    1737 
    1738                 /*increment counter: */
    1739                 count++;
    1740         }
    1741 
    1742         /*Assign output pointers:*/
    1743         *pcount=count;
    1744 }/*}}}*/
    1745 /*FUNCTION Penta::PatchSize{{{1*/
    1746 void  Penta::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
    1747 
    1748         int     i;
    1749         int     numrows  = 0;
    1750         int     numnodes = 0;
    1751 
    1752         /*Go through all the results objects, and update the counters: */
    1753         for (i=0;i<this->results->Size();i++){
    1754                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    1755                 /*first, we have one more result: */
    1756                 numrows++;
    1757                 /*now, how many vertices and how many nodal values for this result? :*/
    1758                 numnodes=elementresult->NumberOfNodalValues(); //ask result object.
    1759         }
    1760 
    1761         /*Assign output pointers:*/
    1762         *pnumrows=numrows;
    1763         *pnumvertices=NUMVERTICES;
    1764         *pnumnodes=numnodes;
    1765 }
    1766 /*}}}*/
    1767 /*FUNCTION Penta::ProcessResultsUnits{{{1*/
    1768 void  Penta::ProcessResultsUnits(void){
    1769 
    1770         int i;
    1771 
    1772         for(i=0;i<this->results->Size();i++){
    1773                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    1774                 elementresult->ProcessUnits(this->parameters);
    1775         }
    1776 }
    1777 /*}}}*/
    1778 /*FUNCTION Penta::SetCurrentConfiguration {{{1*/
    1779 void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
    1780 
    1781         int analysis_counter;
    1782 
    1783         /*go into parameters and get the analysis_counter: */
    1784         parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
    1785 
    1786         /*Get Element type*/
    1787         this->element_type=this->element_type_list[analysis_counter];
    1788 
    1789         /*Pick up nodes */
    1790         if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
    1791         else this->nodes=NULL;
    1792 }
    1793 /*}}}*/
    1794 /*FUNCTION Penta::SurfaceArea {{{1*/
    1795 double Penta::SurfaceArea(void){
    1796 
    1797         int    approximation;
    1798         double S;
    1799         Tria*  tria=NULL;
    1800 
    1801         /*retrieve inputs :*/
    1802         inputs->GetParameterValue(&approximation,ApproximationEnum);
    1803 
    1804         /*If on water, return 0: */
    1805         if(IsOnWater())return 0;
    1806 
    1807         /*Bail out if this element if:
    1808          * -> Non MacAyeal not on the surface
    1809          * -> MacAyeal (2d model) and not on bed) */
    1810         if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
    1811                 return 0;
    1812         }
    1813         else if (approximation==MacAyealApproximationEnum){
    1814 
    1815                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    1816                  * and compute SurfaceArea*/
    1817                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    1818                 S=tria->SurfaceArea();
    1819                 delete tria->matice; delete tria;
    1820                 return S;
    1821         }
    1822         else{
    1823 
    1824                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    1825                 S=tria->SurfaceArea();
    1826                 delete tria->matice; delete tria;
    1827                 return S;
    1828         }
    18295410}
    18305411/*}}}*/
     
    19805561}
    19815562/*}}}*/
    1982 
    1983 /*Penta specific routines: */
    1984 /*FUNCTION Penta::BedNormal {{{1*/
    1985 void Penta::BedNormal(double* bed_normal, double xyz_list[3][3]){
    1986 
    1987         int i;
    1988         double v13[3],v23[3];
    1989         double normal[3];
    1990         double normal_norm;
    1991 
    1992         for (i=0;i<3;i++){
    1993                 v13[i]=xyz_list[0][i]-xyz_list[2][i];
    1994                 v23[i]=xyz_list[1][i]-xyz_list[2][i];
    1995         }
    1996 
    1997         normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
    1998         normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
    1999         normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
    2000         normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
    2001 
    2002         /*Bed normal is opposite to surface normal*/
    2003         *(bed_normal)=-normal[0]/normal_norm;
    2004         *(bed_normal+1)=-normal[1]/normal_norm;
    2005         *(bed_normal+2)=-normal[2]/normal_norm;
    2006 }
    2007 /*}}}*/
    2008 /*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
    2009 ElementMatrix* Penta::CreateKMatrixBalancedthickness(void){
    2010 
    2011         /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
    2012           bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
    2013           the stiffness matrix. */
    2014         if (!IsOnBed() || IsOnWater()) return NULL;
    2015 
    2016         /*Depth Averaging Vx and Vy*/
    2017         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    2018         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    2019 
    2020         /*Spawn Tria element from the base of the Penta: */
    2021         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2022         ElementMatrix* Ke=tria->CreateKMatrixBalancedthickness();
    2023         delete tria->matice; delete tria;
    2024 
    2025         /*Delete Vx and Vy averaged*/
    2026         this->inputs->DeleteInput(VxAverageEnum);
    2027         this->inputs->DeleteInput(VyAverageEnum);
    2028 
    2029         /*clean up and return*/
    2030         return Ke;
    2031 }
    2032 /*}}}*/
    2033 /*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
    2034 ElementMatrix* Penta::CreateKMatrixBalancedvelocities(void){
    2035 
    2036         /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
    2037           bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
    2038           the stiffness matrix. */
    2039         if (!IsOnBed() || IsOnWater()) return NULL;
    2040 
    2041         /*Depth Averaging Vx and Vy*/
    2042         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    2043         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    2044 
    2045         /*Spawn Tria element from the base of the Penta: */
    2046         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2047         ElementMatrix* Ke=tria->CreateKMatrixBalancedvelocities();
    2048         delete tria->matice; delete tria;
    2049 
    2050         /*Delete Vx and Vy averaged*/
    2051         this->inputs->DeleteInput(VxAverageEnum);
    2052         this->inputs->DeleteInput(VyAverageEnum);
    2053 
    2054         /*clean up and return*/
    2055         return Ke;
    2056 }
    2057 /*}}}*/
    2058 /*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattyn{{{1*/
    2059 ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattyn(void){
    2060 
    2061         /*compute all stiffness matrices for this element*/
    2062         ElementMatrix* Ke1=CreateKMatrixCouplingMacAyealPattynViscous();
    2063         ElementMatrix* Ke2=CreateKMatrixCouplingMacAyealPattynFriction();
    2064         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2065 
    2066         /*clean-up and return*/
    2067         delete Ke1;
    2068         delete Ke2;
    2069         return Ke;
    2070 }
    2071 /*}}}*/
    2072 /*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynViscous{{{1*/
    2073 ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynViscous(void){
    2074 
    2075         /*Constants*/
    2076         const int    numdofm=NDOF2*NUMVERTICES2D;
    2077         const int    numdofp=NDOF2*NUMVERTICES;
    2078         const int    numdoftotal=2*NDOF2*NUMVERTICES;
    2079 
    2080         /*Intermediaries */
    2081         int         i,j,ig;
    2082         double      Jdet;
    2083         double      viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
    2084         double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
    2085         double      xyz_list[NUMVERTICES][3];
    2086         double      B[3][numdofp];
    2087         double      Bprime[3][numdofm];
    2088         double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
    2089         double      D_scalar;
    2090         double      Ke_gg[numdofp][numdofm]={0.0}; //local element stiffness matrix
    2091         double      Ke_gg_gaussian[numdofp][numdofm]; //stiffness matrix evaluated at the gaussian point.
    2092         GaussPenta *gauss=NULL;
    2093         GaussTria  *gauss_tria=NULL;
    2094 
    2095         /*Find penta on bed as pattyn must be coupled to the dofs on the bed: */
    2096         Penta* pentabase=GetBasalElement();
    2097         Tria* tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2098 
    2099         /*Initialize Element matrix and return if necessary*/
    2100         if(IsOnWater()) return NULL;
    2101         ElementMatrix* Ke1=new ElementMatrix(pentabase->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
    2102         ElementMatrix* Ke2=new ElementMatrix(this->nodes     ,NUMVERTICES,this->parameters,PattynApproximationEnum);
    2103         ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
    2104         delete Ke1; delete Ke2;
    2105 
    2106         /* Get node coordinates and dof list: */
    2107         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2108         this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
    2109         Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
    2110         Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
    2111         Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
    2112         Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
    2113 
    2114         /* Start  looping on the number of gaussian points: */
    2115         gauss=new GaussPenta(5,5);
    2116         gauss_tria=new GaussTria();
    2117         for (ig=gauss->begin();ig<gauss->end();ig++){
    2118 
    2119                 gauss->GaussPoint(ig);
    2120                 gauss->SynchronizeGaussTria(gauss_tria);
    2121 
    2122                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2123                 GetBMacAyealPattyn(&B[0][0], &xyz_list[0][0], gauss);
    2124                 tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
    2125 
    2126                 this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
    2127                 this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
    2128                 matice->GetViscosity3d(&viscosity, &epsilon[0]);
    2129                 matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
    2130 
    2131                 newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
    2132                 D_scalar=2*newviscosity*gauss->weight*Jdet;
    2133                 for (i=0;i<3;i++) D[i][i]=D_scalar;
    2134 
    2135                 TripleMultiply( &B[0][0],3,numdofp,1,
    2136                                         &D[0][0],3,3,0,
    2137                                         &Bprime[0][0],3,numdofm,0,
    2138                                         &Ke_gg_gaussian[0][0],0);
    2139 
    2140                 for( i=0; i<numdofp; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
    2141         }
    2142         for(i=0;i<numdofp;i++) for(j=0;j<numdofm;j++) Ke->values[(i+2*numdofm)*numdoftotal+j]+=Ke_gg[i][j];
    2143         for(i=0;i<numdofm;i++) for(j=0;j<numdofp;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg[j][i];
    2144 
    2145         /*Clean-up and return*/
    2146         delete tria->matice; delete tria;
    2147         delete gauss;
    2148         delete gauss_tria;
    2149         return Ke;
    2150 }
    2151 /*}}}*/
    2152 /*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynFriction{{{1*/
    2153 ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynFriction(void){
    2154 
    2155         /*Initialize Element matrix and return if necessary*/
    2156         if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
    2157 
    2158         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2159         ElementMatrix* Ke=tria->CreateKMatrixCouplingMacAyealPattynFriction();
    2160         delete tria->matice; delete tria;
    2161 
    2162         return Ke;
    2163 }
    2164 /*}}}*/
    2165 /*FUNCTION Penta::CreateKMatrixCouplingPattynStokes{{{1*/
    2166 ElementMatrix* Penta::CreateKMatrixCouplingPattynStokes(void){
    2167 
    2168         /*compute all stiffness matrices for this element*/
    2169         ElementMatrix* Ke1=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
    2170         ElementMatrix* Ke2=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    2171         ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
    2172         delete Ke1;
    2173         delete Ke2;
    2174         Ke1=CreateKMatrixDiagnosticPattyn();
    2175         Ke2=CreateKMatrixDiagnosticStokes();
    2176 
    2177         /*Constants*/
    2178         const int    numdofp=NDOF2*NUMVERTICES;
    2179         const int    numdofs=NDOF4*NUMVERTICES;
    2180         const int    numdoftotal=(NDOF2+NDOF4)*NUMVERTICES;
    2181         int          i,j;
    2182 
    2183         for(i=0;i<numdofs;i++) for(j=0;j<NUMVERTICES;j++){
    2184                 Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+0]+=Ke2->values[i*numdofs+NDOF4*j+0];
    2185                 Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+1]+=Ke2->values[i*numdofs+NDOF4*j+1];
    2186         }
    2187         for(i=0;i<numdofp;i++) for(j=0;j<NUMVERTICES;j++){
    2188                 Ke->values[i*numdoftotal+numdofp+NDOF4*j+0]+=Ke1->values[i*numdofp+NDOF2*j+0];
    2189                 Ke->values[i*numdoftotal+numdofp+NDOF4*j+1]+=Ke1->values[i*numdofp+NDOF2*j+1];
    2190         }
    2191 
    2192         /*clean-up and return*/
    2193         delete Ke1;
    2194         delete Ke2;
    2195         return Ke;
    2196 }
    2197 /*}}}*/
    2198 /*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
    2199 ElementMatrix* Penta::CreateKMatrixDiagnosticHoriz(void){
    2200 
    2201         int approximation;
    2202         inputs->GetParameterValue(&approximation,ApproximationEnum);
    2203 
    2204         switch(approximation){
    2205                 case MacAyealApproximationEnum:
    2206                         return CreateKMatrixDiagnosticMacAyeal2d();
    2207                 case PattynApproximationEnum:
    2208                         return CreateKMatrixDiagnosticPattyn();
    2209                 case StokesApproximationEnum:
    2210                         return CreateKMatrixDiagnosticStokes();
    2211                 case HutterApproximationEnum:
    2212                         return NULL;
    2213                 case NoneApproximationEnum:
    2214                         return NULL;
    2215                 case MacAyealPattynApproximationEnum:
    2216                         return CreateKMatrixDiagnosticMacAyealPattyn();
    2217                 case PattynStokesApproximationEnum:
    2218                         return CreateKMatrixDiagnosticPattynStokes();
    2219                 default:
    2220                         ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
    2221         }
    2222 }
    2223 /*}}}*/
    2224 /*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
    2225 ElementMatrix* Penta::CreateKMatrixDiagnosticHutter(void){
    2226 
    2227         /*Constants*/
    2228         const int numdof=NDOF2*NUMVERTICES;
    2229 
    2230         /*Intermediaries*/
    2231         int       connectivity[2];
    2232         int       i,i0,i1,j0,j1;
    2233         double    one0,one1;
    2234 
    2235         /*Initialize Element matrix and return if necessary*/
    2236         if(IsOnWater()) return NULL;
    2237         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2238 
    2239         /*Spawn 3 beam elements: */
    2240         for(i=0;i<3;i++){
    2241                 /*2 dofs of first node*/
    2242                 i0=2*i;
    2243                 i1=2*i+1;
    2244                 /*2 dofs of second node*/
    2245                 j0=2*(i+3);
    2246                 j1=2*(i+3)+1;
    2247 
    2248                 /*Find connectivity for the two nodes*/
    2249                 connectivity[0]=nodes[i]->GetConnectivity();
    2250                 connectivity[1]=nodes[i+3]->GetConnectivity();
    2251                 one0=1/(double)connectivity[0];
    2252                 one1=1/(double)connectivity[1];
    2253 
    2254                 /*Create matrix for these two nodes*/
    2255                 if (IsOnBed() && IsOnSurface()){
    2256                         Ke->values[i0*numdof+i0]=one0;
    2257                         Ke->values[i1*numdof+i1]=one0;
    2258                         Ke->values[j0*numdof+i0]=-one1;
    2259                         Ke->values[j0*numdof+j0]=one1;
    2260                         Ke->values[j1*numdof+i1]=-one1;
    2261                         Ke->values[j1*numdof+j1]=one1;
    2262                 }
    2263                 else if (IsOnBed()){
    2264                         Ke->values[i0*numdof+i0]=one0;
    2265                         Ke->values[i1*numdof+i1]=one0;
    2266                         Ke->values[j0*numdof+i0]=-2*one1;
    2267                         Ke->values[j0*numdof+j0]=2*one1;
    2268                         Ke->values[j1*numdof+i1]=-2*one1;
    2269                         Ke->values[j1*numdof+j1]=2*one1;
    2270                 }
    2271                 else if (IsOnSurface()){
    2272                         Ke->values[j0*numdof+i0]=-one1;
    2273                         Ke->values[j0*numdof+j0]=one1;
    2274                         Ke->values[j1*numdof+i1]=-one1;
    2275                         Ke->values[j1*numdof+j1]=one1;
    2276                 }
    2277                 else{ //node is on two horizontal layers and beams include the values only once, so the have to use half of the connectivity
    2278                         Ke->values[j0*numdof+i0]=-2*one1;
    2279                         Ke->values[j0*numdof+j0]=2*one1;
    2280                         Ke->values[j1*numdof+i1]=-2*one1;
    2281                         Ke->values[j1*numdof+j1]=2*one1;
    2282                 }
    2283         }
    2284 
    2285         /*Clean up and return*/
    2286         return Ke;
    2287 }
    2288 /*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal2d{{{1*/
    2289 ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal2d(void){
    2290        
    2291         /*Figure out if this penta is collapsed. If so, then bailout, except if it is at the
    2292           bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
    2293           the stiffness matrix. */
    2294         if (!IsOnBed() || IsOnWater()) return NULL;
    2295 
    2296         /*Depth Averaging B*/
    2297         this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
    2298 
    2299         /*Call Tria function*/
    2300         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2301         ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyeal();
    2302         delete tria->matice; delete tria;
    2303 
    2304         /*Delete B averaged*/
    2305         this->matice->inputs->DeleteInput(RheologyBbarEnum);
    2306 
    2307         /*clean up and return*/
    2308         return Ke;
    2309 }
    2310 /*}}}*/
    2311 /*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3d{{{1*/
    2312 ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3d(void){
    2313 
    2314         /*compute all stiffness matrices for this element*/
    2315         ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3dViscous();
    2316         ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyeal3dFriction();
    2317         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2318 
    2319         /*clean-up and return*/
    2320         delete Ke1;
    2321         delete Ke2;
    2322         return Ke;
    2323 }
    2324 /*}}}*/
    2325 /*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dViscous{{{1*/
    2326 ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dViscous(void){
    2327 
    2328         /*Constants*/
    2329         const int    numdof2d=2*NUMVERTICES2D;
    2330 
    2331         /*Intermediaries */
    2332         int         i,j,ig;
    2333         double      Jdet;
    2334         double      viscosity, oldviscosity, newviscosity, viscosity_overshoot;
    2335         double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
    2336         double      xyz_list[NUMVERTICES][3];
    2337         double      B[3][numdof2d];
    2338         double      Bprime[3][numdof2d];
    2339         double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
    2340         double      D_scalar;
    2341         double      Ke_gg_gaussian[numdof2d][numdof2d]; //stiffness matrix evaluated at the gaussian point.
    2342         Tria*       tria=NULL;
    2343         Penta*      pentabase=NULL;
    2344         GaussPenta *gauss=NULL;
    2345         GaussTria  *gauss_tria=NULL;
    2346 
    2347         /*Find penta on bed as this is a macayeal elements: */
    2348         pentabase=GetBasalElement();
    2349         tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2350 
    2351         /*Initialize Element matrix and return if necessary*/
    2352         if(IsOnWater()) return NULL;
    2353         ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,MacAyealApproximationEnum);
    2354 
    2355         /*Retrieve all inputs and parameters*/
    2356         GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES);
    2357         this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
    2358         Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
    2359         Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
    2360         Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
    2361         Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
    2362 
    2363         /* Start  looping on the number of gaussian points: */
    2364         gauss=new GaussPenta(5,5);
    2365         gauss_tria=new GaussTria();
    2366         for (ig=gauss->begin();ig<gauss->end();ig++){
    2367 
    2368                 gauss->GaussPoint(ig);
    2369                 gauss->SynchronizeGaussTria(gauss_tria);
    2370 
    2371                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2372                 tria->GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss_tria);
    2373                 tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
    2374 
    2375                 this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
    2376                 this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
    2377                 matice->GetViscosity3d(&viscosity, &epsilon[0]);
    2378                 matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
    2379 
    2380                 newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
    2381                 D_scalar=2*newviscosity*gauss->weight*Jdet;
    2382                 for (i=0;i<3;i++) D[i][i]=D_scalar;
    2383 
    2384                 TripleMultiply( &B[0][0],3,numdof2d,1,
    2385                                         &D[0][0],3,3,0,
    2386                                         &Bprime[0][0],3,numdof2d,0,
    2387                                         &Ke_gg_gaussian[0][0],0);
    2388 
    2389                 for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof2d+j]+=Ke_gg_gaussian[i][j];
    2390         }
    2391 
    2392         /*Clean up and return*/
    2393         delete tria->matice;
    2394         delete tria;
    2395         delete gauss_tria;
    2396         delete gauss;
    2397         return Ke;
    2398 }
    2399 /*}}}*/
    2400 /*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dFriction{{{1*/
    2401 ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dFriction(void){
    2402 
    2403         /*Initialize Element matrix and return if necessary*/
    2404         if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
    2405 
    2406         /*Build a tria element using the 3 grids of the base of the penta. Then use
    2407          * the tria functionality to build a friction stiffness matrix on these 3
    2408          * grids: */
    2409         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2410         ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
    2411         delete tria->matice; delete tria;
    2412 
    2413         /*clean-up and return*/
    2414         return Ke;
    2415 }
    2416 /*}}}*/
    2417 /*FUNCTION Penta::CreateKMatrixDiagnosticMacAyealPattyn{{{1*/
    2418 ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyealPattyn(void){
    2419 
    2420         /*compute all stiffness matrices for this element*/
    2421         ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3d();
    2422         ElementMatrix* Ke2=CreateKMatrixDiagnosticPattyn();
    2423         ElementMatrix* Ke3=CreateKMatrixCouplingMacAyealPattyn();
    2424         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
    2425 
    2426         /*clean-up and return*/
    2427         delete Ke1;
    2428         delete Ke2;
    2429         delete Ke3;
    2430         return Ke;
    2431 }
    2432 /*}}}*/
    2433 /*FUNCTION Penta::CreateKMatrixDiagnosticPattyn{{{1*/
    2434 ElementMatrix* Penta::CreateKMatrixDiagnosticPattyn(void){
    2435 
    2436         /*compute all stiffness matrices for this element*/
    2437         ElementMatrix* Ke1=CreateKMatrixDiagnosticPattynViscous();
    2438         ElementMatrix* Ke2=CreateKMatrixDiagnosticPattynFriction();
    2439         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2440 
    2441         /*clean-up and return*/
    2442         delete Ke1;
    2443         delete Ke2;
    2444         return Ke;
    2445 }
    2446 /*}}}*/
    2447 /*FUNCTION Penta::CreateKMatrixDiagnosticPattynViscous{{{1*/
    2448 ElementMatrix* Penta::CreateKMatrixDiagnosticPattynViscous(void){
    2449 
    2450         /*Constants*/
    2451         const int    numdof=NDOF2*NUMVERTICES;
    2452 
    2453         /*Intermediaries */
    2454         int        i,j,ig;
    2455         int        approximation;
    2456         double     xyz_list[NUMVERTICES][3];
    2457         double     Jdet;
    2458         double     viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
    2459         double     epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
    2460         double     D_scalar;
    2461         double     D[5][5]={0.0};            // material matrix, simple scalar matrix.
    2462         double     B[5][numdof];
    2463         double     Bprime[5][numdof];
    2464         double     Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
    2465         Tria*      tria=NULL;
    2466         GaussPenta *gauss=NULL;
    2467 
    2468         /*Initialize Element matrix and return if necessary*/
    2469         if(IsOnWater()) return NULL;
    2470         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
    2471 
    2472         /*Retrieve all inputs and parameters*/
    2473         inputs->GetParameterValue(&approximation,ApproximationEnum);
    2474         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2475         this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
    2476         Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
    2477         Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
    2478         Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
    2479         Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
    2480 
    2481         /* Start  looping on the number of gaussian points: */
    2482         gauss=new GaussPenta(5,5);
    2483         for (ig=gauss->begin();ig<gauss->end();ig++){
    2484 
    2485                 gauss->GaussPoint(ig);
    2486 
    2487                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2488                 GetBPattyn(&B[0][0], &xyz_list[0][0], gauss);
    2489                 GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss);
    2490 
    2491                 this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
    2492                 this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
    2493                 matice->GetViscosity3d(&viscosity, &epsilon[0]);
    2494                 matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
    2495                 newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
    2496 
    2497                 D_scalar=2*newviscosity*gauss->weight*Jdet;
    2498                 for (i=0;i<5;i++) D[i][i]=D_scalar;
    2499 
    2500                 TripleMultiply( &B[0][0],5,numdof,1,
    2501                                         &D[0][0],5,5,0,
    2502                                         &Bprime[0][0],5,numdof,0,
    2503                                         &Ke_gg_gaussian[0][0],0);
    2504 
    2505                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    2506         }
    2507 
    2508         /*Clean up and return*/
    2509         delete gauss;
    2510         return Ke;
    2511 }
    2512 /*}}}*/
    2513 /*FUNCTION Penta::CreateKMatrixDiagnosticPattynFriction{{{1*/
    2514 ElementMatrix* Penta::CreateKMatrixDiagnosticPattynFriction(void){
    2515 
    2516         /*Initialize Element matrix and return if necessary*/
    2517         if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
    2518 
    2519         /*Build a tria element using the 3 grids of the base of the penta. Then use
    2520          * the tria functionality to build a friction stiffness matrix on these 3
    2521          * grids: */
    2522         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2523         ElementMatrix* Ke=tria->CreateKMatrixDiagnosticPattynFriction();
    2524         delete tria->matice; delete tria;
    2525 
    2526         /*clean-up and return*/
    2527         return Ke;
    2528 }
    2529 /*}}}*/
    2530 /*FUNCTION Penta::CreateKMatrixDiagnosticPattynStokes{{{1*/
    2531 ElementMatrix* Penta::CreateKMatrixDiagnosticPattynStokes(void){
    2532 
    2533         /*compute all stiffness matrices for this element*/
    2534         ElementMatrix* Ke1=CreateKMatrixDiagnosticPattyn();
    2535         ElementMatrix* Ke2=CreateKMatrixDiagnosticStokes();
    2536         ElementMatrix* Ke3=CreateKMatrixCouplingPattynStokes();
    2537         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
    2538 
    2539         /*clean-up and return*/
    2540         delete Ke1;
    2541         delete Ke2;
    2542         delete Ke3;
    2543         return Ke;
    2544 }
    2545 /*}}}*/
    2546 /*FUNCTION Penta::CreateKMatrixDiagnosticStokes{{{1*/
    2547 ElementMatrix* Penta::CreateKMatrixDiagnosticStokes(void){
    2548 
    2549         /*compute all stiffness matrices for this element*/
    2550         ElementMatrix* Ke1=CreateKMatrixDiagnosticStokesViscous();
    2551         ElementMatrix* Ke2=CreateKMatrixDiagnosticStokesFriction();
    2552         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2553 
    2554         /*clean-up and return*/
    2555         delete Ke1;
    2556         delete Ke2;
    2557         return Ke;
    2558 }
    2559 /*}}}*/
    2560 /*FUNCTION Penta::CreateKMatrixDiagnosticStokesViscous {{{1*/
    2561 ElementMatrix* Penta::CreateKMatrixDiagnosticStokesViscous(void){
    2562 
    2563         /*Intermediaries */
    2564         int        i,j,ig,approximation;
    2565         double     Jdet,viscosity,stokesreconditioning;
    2566         double     xyz_list[NUMVERTICES][3];
    2567         double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    2568         double     B[8][27];
    2569         double     B_prime[8][27];
    2570         double     D_scalar;
    2571         double     D[8][8]={0.0};
    2572         double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble
    2573         double     Ke_gaussian[27][27];
    2574         GaussPenta *gauss=NULL;
    2575 
    2576         /*If on water or not Stokes, skip stiffness: */
    2577         inputs->GetParameterValue(&approximation,ApproximationEnum);
    2578         if(IsOnWater() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
    2579         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    2580 
    2581         /*Retrieve all inputs and parameters*/
    2582         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2583         parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    2584         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    2585         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    2586         Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
    2587 
    2588         /* Start  looping on the number of gaussian points: */
    2589         gauss=new GaussPenta(5,5);
    2590         for (ig=gauss->begin();ig<gauss->end();ig++){
    2591 
    2592                 gauss->GaussPoint(ig);
    2593 
    2594                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2595                 GetBStokes(&B[0][0],&xyz_list[0][0],gauss);
    2596                 GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0],gauss);
    2597 
    2598                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    2599                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    2600 
    2601                 D_scalar=gauss->weight*Jdet;
    2602                 for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
    2603                 for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
    2604 
    2605                 TripleMultiply( &B[0][0],8,27,1,
    2606                                         &D[0][0],8,8,0,
    2607                                         &B_prime[0][0],8,27,0,
    2608                                         &Ke_gaussian[0][0],0);
    2609 
    2610                 for(i=0;i<27;i++) for(j=0;j<27;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
    2611         }
    2612 
    2613         /*Condensation*/
    2614         ReduceMatrixStokes(Ke->values, &Ke_temp[0][0]);
    2615 
    2616         /*Clean up and return*/
    2617         delete gauss;
    2618         return Ke;
    2619 }
    2620 /*}}}*/
    2621 /*FUNCTION Penta::CreateKMatrixDiagnosticStokesFriction {{{1*/
    2622 ElementMatrix* Penta::CreateKMatrixDiagnosticStokesFriction(void){
    2623 
    2624         /*Constants*/
    2625         const int numdof=NUMVERTICES*NDOF4;
    2626         const int numdof2d=NUMVERTICES2D*NDOF4;
    2627 
    2628         /*Intermediaries */
    2629         int        i,j,ig;
    2630         int        analysis_type,approximation;
    2631         double     stokesreconditioning;
    2632         double     viscosity,alpha2_gauss,Jdet2d;
    2633         double    bed_normal[3];
    2634         double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    2635         double     xyz_list[NUMVERTICES][3];
    2636         double    xyz_list_tria[NUMVERTICES2D][3];
    2637         double     LStokes[14][numdof2d];
    2638         double     LprimeStokes[14][numdof2d];
    2639         double     DLStokes[14][14]={0.0};
    2640         double     Ke_drag_gaussian[numdof2d][numdof2d];
    2641         Friction*  friction=NULL;
    2642         GaussPenta *gauss=NULL;
    2643 
    2644         /*If on water or not Stokes, skip stiffness: */
    2645         inputs->GetParameterValue(&approximation,ApproximationEnum);
    2646         if(IsOnWater() || IsOnShelf() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
    2647         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    2648 
    2649         /*Retrieve all inputs and parameters*/
    2650         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2651         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    2652         parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    2653         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    2654         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    2655         Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
    2656         for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
    2657 
    2658         /*build friction object, used later on: */
    2659         friction=new Friction("3d",inputs,matpar,analysis_type);
    2660 
    2661         /* Start  looping on the number of gaussian points: */
    2662         gauss=new GaussPenta(0,1,2,2);
    2663         for (ig=gauss->begin();ig<gauss->end();ig++){
    2664 
    2665                 gauss->GaussPoint(ig);
    2666 
    2667                 GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
    2668                 GetLStokes(&LStokes[0][0], gauss);
    2669                 GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss);
    2670 
    2671                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    2672                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    2673 
    2674                 BedNormal(&bed_normal[0],xyz_list_tria);
    2675                 friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
    2676 
    2677                 DLStokes[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
    2678                 DLStokes[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
    2679                 DLStokes[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
    2680                 DLStokes[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
    2681                 DLStokes[4][4]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
    2682                 DLStokes[5][5]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
    2683                 DLStokes[6][6]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0];
    2684                 DLStokes[7][7]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1];
    2685                 DLStokes[8][8]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[2];
    2686                 DLStokes[9][9]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0]/2.0;
    2687                 DLStokes[10][10]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1]/2.0;
    2688                 DLStokes[11][11]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[0];
    2689                 DLStokes[12][12]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[1];
    2690                 DLStokes[13][13]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[2];
    2691 
    2692                 TripleMultiply( &LStokes[0][0],14,numdof2d,1,
    2693                                         &DLStokes[0][0],14,14,0,
    2694                                         &LprimeStokes[0][0],14,numdof2d,0,
    2695                                         &Ke_drag_gaussian[0][0],0);
    2696 
    2697                 for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof+j]+=Ke_drag_gaussian[i][j];
    2698         }
    2699 
    2700         /*Clean up and return*/
    2701         delete gauss;
    2702         delete friction;
    2703         return Ke;
    2704 }
    2705 /*}}}*/
    2706 /*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
    2707 ElementMatrix* Penta::CreateKMatrixDiagnosticVert(void){
    2708 
    2709         /*compute all stiffness matrices for this element*/
    2710         ElementMatrix* Ke1=CreateKMatrixDiagnosticVertVolume();
    2711         ElementMatrix* Ke2=CreateKMatrixDiagnosticVertSurface();
    2712         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2713 
    2714         /*clean-up and return*/
    2715         delete Ke1;
    2716         delete Ke2;
    2717         return Ke;
    2718 }
    2719 /*}}}*/
    2720 /*FUNCTION Penta::CreateKMatrixDiagnosticVertVolume {{{1*/
    2721 ElementMatrix* Penta::CreateKMatrixDiagnosticVertVolume(void){
    2722 
    2723         /*Constants*/
    2724         const int    numdof=NDOF1*NUMVERTICES;
    2725 
    2726         /*Intermediaries */
    2727         int         i,j,ig;
    2728         double      Jdet;
    2729         double      xyz_list[NUMVERTICES][3];
    2730         double      B[NDOF1][NUMVERTICES];
    2731         double      Bprime[NDOF1][NUMVERTICES];
    2732         double      DL_scalar;
    2733         double      Ke_gg[numdof][numdof]={0.0};
    2734         GaussPenta  *gauss=NULL;
    2735 
    2736         /*Initialize Element matrix and return if necessary*/
    2737         if(IsOnWater()) return NULL;
    2738         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2739 
    2740         /*Retrieve all inputs and parameters*/
    2741         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2742 
    2743         /* Start  looping on the number of gaussian points: */
    2744         gauss=new GaussPenta(2,2);
    2745         for (ig=gauss->begin();ig<gauss->end();ig++){
    2746 
    2747                 gauss->GaussPoint(ig);
    2748 
    2749                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2750                 GetBVert(&B[0][0], &xyz_list[0][0], gauss);
    2751                 GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss);
    2752 
    2753                 DL_scalar=gauss->weight*Jdet;
    2754 
    2755                 TripleMultiply( &B[0][0],1,NUMVERTICES,1,
    2756                                         &DL_scalar,1,1,0,
    2757                                         &Bprime[0][0],1,NUMVERTICES,0,
    2758                                         &Ke_gg[0][0],0);
    2759 
    2760                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
    2761         }
    2762 
    2763         /*Clean up and return*/
    2764         delete gauss;
    2765         return Ke;
    2766 }
    2767 /*}}}*/
    2768 /*FUNCTION Penta::CreateKMatrixDiagnosticVertSurface {{{1*/
    2769 ElementMatrix* Penta::CreateKMatrixDiagnosticVertSurface(void){
    2770 
    2771         if (!IsOnSurface() || IsOnWater()) return NULL;
    2772 
    2773         /*Call Tria function*/
    2774         Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
    2775         ElementMatrix* Ke=tria->CreateKMatrixDiagnosticVertSurface();
    2776         delete tria->matice; delete tria;
    2777 
    2778         /*clean up and return*/
    2779         return Ke;
    2780 }
    2781 /*}}}*/
    2782 /*FUNCTION Penta::CreateKMatrixMelting {{{1*/
    2783 ElementMatrix* Penta::CreateKMatrixMelting(void){
    2784 
    2785         if (!IsOnBed() || IsOnWater()) return NULL;
    2786 
    2787         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2788         ElementMatrix* Ke=tria->CreateKMatrixMelting();
    2789 
    2790         delete tria->matice; delete tria;
    2791         return Ke;
    2792 }
    2793 /*}}}*/
    2794 /*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
    2795 ElementMatrix* Penta::CreateKMatrixPrognostic(void){
    2796 
    2797         if (!IsOnBed() || IsOnWater()) return NULL;
    2798 
    2799         /*Depth Averaging Vx and Vy*/
    2800         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    2801         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    2802 
    2803         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2804         ElementMatrix* Ke=tria->CreateKMatrixPrognostic();
    2805         delete tria->matice; delete tria;
    2806 
    2807         /*Delete Vx and Vy averaged*/
    2808         this->inputs->DeleteInput(VxAverageEnum);
    2809         this->inputs->DeleteInput(VyAverageEnum);
    2810 
    2811         /*clean up and return*/
    2812         return Ke;
    2813 }
    2814 /*}}}*/
    2815 /*FUNCTION Penta::CreateKMatrixSlope {{{1*/
    2816 ElementMatrix* Penta::CreateKMatrixSlope(void){
    2817 
    2818         if (!IsOnBed() || IsOnWater()) return NULL;
    2819 
    2820         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2821         ElementMatrix* Ke=tria->CreateKMatrixSlope();
    2822         delete tria->matice; delete tria;
    2823 
    2824         /*clean up and return*/
    2825         return Ke;
    2826 }
    2827 /*}}}*/
    2828 /*FUNCTION Penta::CreateKMatrixThermal {{{1*/
    2829 ElementMatrix* Penta::CreateKMatrixThermal(void){
    2830 
    2831         /*compute all stiffness matrices for this element*/
    2832         ElementMatrix* Ke1=CreateKMatrixThermalVolume();
    2833         ElementMatrix* Ke2=CreateKMatrixThermalShelf();
    2834         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2835 
    2836         /*clean-up and return*/
    2837         delete Ke1;
    2838         delete Ke2;
    2839         return Ke;
    2840 }
    2841 /*}}}*/
    2842 /*FUNCTION Penta::CreateKMatrixThermalVolume {{{1*/
    2843 ElementMatrix* Penta::CreateKMatrixThermalVolume(void){
    2844 
    2845         /*Constants*/
    2846         const int    numdof=NDOF1*NUMVERTICES;
    2847 
    2848         /*Intermediaries */
    2849         int        artdiff;
    2850         int        i,j,ig,found=0;
    2851         double     Jdet,u,v,w,epsvel;
    2852         double     gravity,rho_ice,rho_water;
    2853         double     heatcapacity,thermalconductivity,dt;
    2854         double     tau_parameter,diameter;
    2855         double     xyz_list[NUMVERTICES][3];
    2856         double     B[3][numdof];
    2857         double     Bprime[3][numdof];
    2858         double     B_conduct[3][numdof];
    2859         double     B_advec[3][numdof];
    2860         double     B_artdiff[2][numdof];
    2861         double     Bprime_advec[3][numdof];
    2862         double     L[numdof];
    2863         double     dh1dh6[3][6];
    2864         double     D_scalar_conduct,D_scalar_advec;
    2865         double     D_scalar_trans,D_scalar_artdiff;
    2866         double     D[3][3];
    2867         double     K[2][2]={0.0};
    2868         double     Ke_gaussian_conduct[numdof][numdof];
    2869         double     Ke_gaussian_advec[numdof][numdof];
    2870         double     Ke_gaussian_artdiff[numdof][numdof];
    2871         double     Ke_gaussian_transient[numdof][numdof];
    2872         Tria*      tria=NULL;
    2873         GaussPenta *gauss=NULL;
    2874 
    2875         /*Initialize Element matrix and return if necessary*/
    2876         if(IsOnWater()) return NULL;
    2877         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2878 
    2879         /*Retrieve all inputs and parameters*/
    2880         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2881         rho_water=matpar->GetRhoWater();
    2882         rho_ice=matpar->GetRhoIce();
    2883         gravity=matpar->GetG();
    2884         heatcapacity=matpar->GetHeatCapacity();
    2885         thermalconductivity=matpar->GetThermalConductivity();
    2886         this->inputs->GetParameterValue(&dt,DtEnum);
    2887         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    2888         this->parameters->FindParam(&epsvel,EpsVelEnum);
    2889         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    2890         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    2891         Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
    2892         if (artdiff==2) diameter=MinEdgeLength(xyz_list);
    2893 
    2894         /* Start  looping on the number of gaussian points: */
    2895         gauss=new GaussPenta(2,2);
    2896         for (ig=gauss->begin();ig<gauss->end();ig++){
    2897 
    2898                 gauss->GaussPoint(ig);
    2899 
    2900                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    2901 
    2902                 /*Conduction: */
    2903 
    2904                 GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss);
    2905 
    2906                 D_scalar_conduct=gauss->weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
    2907                 if(dt) D_scalar_conduct=D_scalar_conduct*dt;
    2908 
    2909                 D[0][0]=D_scalar_conduct; D[0][1]=0; D[0][2]=0;
    2910                 D[1][0]=0; D[1][1]=D_scalar_conduct; D[1][2]=0;
    2911                 D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar_conduct;
    2912 
    2913                 TripleMultiply(&B_conduct[0][0],3,numdof,1,
    2914                                         &D[0][0],3,3,0,
    2915                                         &B_conduct[0][0],3,numdof,0,
    2916                                         &Ke_gaussian_conduct[0][0],0);
    2917 
    2918                 /*Advection: */
    2919 
    2920                 GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss);
    2921                 GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss);
    2922 
    2923                 vx_input->GetParameterValue(&u, gauss);
    2924                 vy_input->GetParameterValue(&v, gauss);
    2925                 vz_input->GetParameterValue(&w, gauss);
    2926 
    2927                 D_scalar_advec=gauss->weight*Jdet;
    2928                 if(dt) D_scalar_advec=D_scalar_advec*dt;
    2929 
    2930                 D[0][0]=D_scalar_advec*u;D[0][1]=0;         D[0][2]=0;
    2931                 D[1][0]=0;         D[1][1]=D_scalar_advec*v;D[1][2]=0;
    2932                 D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar_advec*w;
    2933 
    2934                 TripleMultiply(&B_advec[0][0],3,numdof,1,
    2935                                         &D[0][0],3,3,0,
    2936                                         &Bprime_advec[0][0],3,numdof,0,
    2937                                         &Ke_gaussian_advec[0][0],0);
    2938 
    2939                 /*Transient: */
    2940 
    2941                 if(dt){
    2942                         GetNodalFunctionsP1(&L[0], gauss);
    2943                         D_scalar_trans=gauss->weight*Jdet;
    2944                         D_scalar_trans=D_scalar_trans;
    2945 
    2946                         TripleMultiply(&L[0],numdof,1,0,
    2947                                                 &D_scalar_trans,1,1,0,
    2948                                                 &L[0],1,numdof,0,
    2949                                                 &Ke_gaussian_transient[0][0],0);
    2950                 }
    2951                 else{
    2952                         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_transient[i][j]=0;
    2953                 }
    2954 
    2955                 /*Artifficial diffusivity*/
    2956 
    2957                 if(artdiff==1){
    2958                         /*Build K: */
    2959                         D_scalar_artdiff=gauss->weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
    2960                         if(dt) D_scalar_artdiff=D_scalar_artdiff*dt;
    2961                         K[0][0]=D_scalar_artdiff*pow(u,2);       K[0][1]=D_scalar_artdiff*fabs(u)*fabs(v);
    2962                         K[1][0]=D_scalar_artdiff*fabs(u)*fabs(v);K[1][1]=D_scalar_artdiff*pow(v,2);
    2963 
    2964                         GetBArtdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss);
    2965 
    2966                         TripleMultiply(&B_artdiff[0][0],2,numdof,1,
    2967                                                 &K[0][0],2,2,0,
    2968                                                 &B_artdiff[0][0],2,numdof,0,
    2969                                                 &Ke_gaussian_artdiff[0][0],0);
    2970                 }
    2971                 else if(artdiff==2){
    2972 
    2973                         GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
    2974 
    2975                         tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
    2976 
    2977                         for(i=0;i<numdof;i++){
    2978                                 for(j=0;j<numdof;j++){
    2979                                         Ke_gaussian_artdiff[i][j]=tau_parameter*D_scalar_advec*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i])*(u*dh1dh6[0][j]+v*dh1dh6[1][j]+w*dh1dh6[2][j]);
    2980                                 }
    2981                         }
    2982                         if(dt){
    2983                                 for(i=0;i<numdof;i++){
    2984                                         for(j=0;j<numdof;j++){
    2985                                                 Ke_gaussian_artdiff[i][j]+=tau_parameter*D_scalar_trans*L[j]*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
    2986                                         }
    2987                                 }
    2988                         }
    2989                 }
    2990                 else{
    2991                         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_artdiff[i][j]=0;
    2992                 }
    2993 
    2994                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
    2995         }
    2996 
    2997         /*Clean up and return*/
    2998         delete gauss;
    2999         return Ke;
    3000 }
    3001 /*}}}*/
    3002 /*FUNCTION Penta::CreateKMatrixThermalShelf {{{1*/
    3003 ElementMatrix* Penta::CreateKMatrixThermalShelf(void){
    3004 
    3005         if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
    3006 
    3007         /*Call Tria function*/
    3008         Tria* tria=(Tria*)SpawnTria(0,1,2);
    3009         ElementMatrix* Ke=tria->CreateKMatrixThermal();
    3010         delete tria->matice; delete tria;
    3011 
    3012         return Ke;
    3013 }
    3014 /*}}}*/
    3015 /*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
    3016 ElementVector* Penta::CreatePVectorAdjointHoriz(void){
    3017 
    3018         int approximation;
    3019         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3020 
    3021         switch(approximation){
    3022                 case MacAyealApproximationEnum:
    3023                         return CreatePVectorAdjointMacAyeal();
    3024                 case PattynApproximationEnum:
    3025                         return CreatePVectorAdjointPattyn();
    3026                 case NoneApproximationEnum:
    3027                         return NULL;
    3028                 case StokesApproximationEnum:
    3029                         return CreatePVectorAdjointStokes();
    3030                 default:
    3031                         ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
    3032         }
    3033 }
    3034 /*}}}*/
    3035 /*FUNCTION Penta::CreatePVectorAdjointMacAyeal{{{1*/
    3036 ElementVector* Penta::CreatePVectorAdjointMacAyeal(){
    3037 
    3038         if (!IsOnBed() || IsOnWater()) return NULL;
    3039 
    3040         /*Call Tria function*/
    3041         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3042         ElementVector* pe=tria->CreatePVectorAdjointHoriz();
    3043         delete tria->matice; delete tria;
    3044 
    3045         /*clean up and return*/
    3046         return pe;
    3047 }
    3048 /*}}}*/
    3049 /*FUNCTION Penta::CreatePVectorAdjointPattyn{{{1*/
    3050 ElementVector* Penta::CreatePVectorAdjointPattyn(void){
    3051 
    3052         if (!IsOnSurface() || IsOnWater()) return NULL;
    3053 
    3054         /*Call Tria function*/
    3055         Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    3056         ElementVector* pe=tria->CreatePVectorAdjointHoriz();
    3057         delete tria->matice; delete tria;
    3058 
    3059         /*clean up and return*/
    3060         return pe;
    3061 }
    3062 /*}}}*/
    3063 /*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
    3064 ElementVector* Penta::CreatePVectorBalancedthickness(void){
    3065 
    3066         if (!IsOnBed() || IsOnWater()) return NULL;
    3067 
    3068         /*Depth Averaging Vx and Vy*/
    3069         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    3070         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    3071 
    3072         /*Call Tria function*/
    3073         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3074         ElementVector* pe=tria->CreatePVectorBalancedthickness();
    3075         delete tria->matice; delete tria;
    3076 
    3077         /*Delete Vx and Vy averaged*/
    3078         this->inputs->DeleteInput(VxAverageEnum);
    3079         this->inputs->DeleteInput(VyAverageEnum);
    3080 
    3081         /*Clean up and return*/
    3082         return pe;
    3083 }
    3084 /*}}}*/
    3085 /*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
    3086 ElementVector* Penta::CreatePVectorBalancedvelocities(void){
    3087 
    3088         if (!IsOnBed() || IsOnWater()) return NULL;
    3089 
    3090         /*Depth Averaging Vx and Vy*/
    3091         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    3092         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    3093 
    3094         /*Call Tria function*/
    3095         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3096         ElementVector* pe=tria->CreatePVectorBalancedvelocities();
    3097         delete tria->matice; delete tria;
    3098 
    3099         /*Delete Vx and Vy averaged*/
    3100         this->inputs->DeleteInput(VxAverageEnum);
    3101         this->inputs->DeleteInput(VyAverageEnum);
    3102 
    3103         /*Clean up and return*/
    3104         return pe;
    3105 }
    3106 /*}}}*/
    3107 /*FUNCTION Penta::CreatePVectorCouplingPattynStokes {{{1*/
    3108 ElementVector* Penta::CreatePVectorCouplingPattynStokes(void){
    3109 
    3110         /*compute all load vectors for this element*/
    3111         ElementVector* pe1=CreatePVectorCouplingPattynStokesViscous();
    3112         ElementVector* pe2=CreatePVectorCouplingPattynStokesFriction();
    3113         ElementVector* pe =new ElementVector(pe1,pe2);
    3114 
    3115         /*clean-up and return*/
    3116         delete pe1;
    3117         delete pe2;
    3118         return pe;
    3119 }
    3120 /*}}}*/
    3121 /*FUNCTION Penta::CreatePVectorCouplingPattynStokesViscous {{{1*/
    3122 ElementVector* Penta::CreatePVectorCouplingPattynStokesViscous(void){
    3123 
    3124         /*Constants*/
    3125         const int   numdof=NUMVERTICES*NDOF4;
    3126 
    3127         /*Intermediaries */
    3128         int         i,j,ig;
    3129         int         approximation;
    3130         double      viscosity,Jdet;
    3131         double      stokesreconditioning;
    3132         double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    3133         double      dw[3];
    3134         double      xyz_list[NUMVERTICES][3];
    3135         double      l1l6[6]; //for the six nodes of the penta
    3136         double      dh1dh6[3][6]; //for the six nodes of the penta
    3137         GaussPenta *gauss=NULL;
    3138 
    3139         /*Initialize Element vector and return if necessary*/
    3140         if(IsOnWater()) return NULL;
    3141         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3142         if(approximation!=PattynStokesApproximationEnum) return NULL;
    3143         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    3144 
    3145         /*Retrieve all inputs and parameters*/
    3146         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3147         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    3148         Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
    3149         Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
    3150         Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
    3151         Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
    3152 
    3153         /* Start  looping on the number of gaussian points: */
    3154         gauss=new GaussPenta(5,5);
    3155         for (ig=gauss->begin();ig<gauss->end();ig++){
    3156 
    3157                 gauss->GaussPoint(ig);
    3158 
    3159                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    3160                 GetNodalFunctionsP1(&l1l6[0], gauss);
    3161                 GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
    3162 
    3163                 vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
    3164 
    3165                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    3166                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3167 
    3168                 for(i=0;i<NUMVERTICES;i++){
    3169                         pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dh1dh6[2][i];
    3170                         pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dh1dh6[2][i];
    3171                         pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dh1dh6[0][i]+dw[1]*dh1dh6[1][i]+2*dw[2]*dh1dh6[2][i]);
    3172                         pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*l1l6[i];
    3173                 }
    3174         }
    3175 
    3176         /*Clean up and return*/
    3177         delete gauss;
    3178         return pe;
    3179 }
    3180 /*}}}*/
    3181 /*FUNCTION Penta::CreatePVectorCouplingPattynStokesFriction{{{1*/
    3182 ElementVector* Penta::CreatePVectorCouplingPattynStokesFriction(void){
    3183 
    3184         /*Constants*/
    3185         const int numdof=NUMVERTICES*NDOF4;
    3186 
    3187         /*Intermediaries*/
    3188         int         i,j,ig;
    3189         int         approximation,analysis_type;
    3190         double      Jdet,Jdet2d;
    3191         double      stokesreconditioning;
    3192         double     bed_normal[3];
    3193         double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    3194         double      viscosity, w, alpha2_gauss;
    3195         double      dw[3];
    3196         double     xyz_list_tria[NUMVERTICES2D][3];
    3197         double      xyz_list[NUMVERTICES][3];
    3198         double      l1l6[6]; //for the six nodes of the penta
    3199         Tria*       tria=NULL;
    3200         Friction*   friction=NULL;
    3201         GaussPenta  *gauss=NULL;
    3202 
    3203         /*Initialize Element vector and return if necessary*/
    3204         if(IsOnWater() || !IsOnBed() || IsOnShelf()) return NULL;
    3205         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3206         if(approximation!=PattynStokesApproximationEnum) return NULL;
    3207         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    3208 
    3209         /*Retrieve all inputs and parameters*/
    3210         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3211         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    3212         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    3213         Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
    3214         Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
    3215         Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
    3216         Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
    3217 
    3218         for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
    3219 
    3220         /*build friction object, used later on: */
    3221         friction=new Friction("3d",inputs,matpar,analysis_type);
    3222 
    3223         /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    3224         gauss=new GaussPenta(0,1,2,2);
    3225         for(ig=gauss->begin();ig<gauss->end();ig++){
    3226 
    3227                 gauss->GaussPoint(ig);
    3228 
    3229                 GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
    3230                 GetNodalFunctionsP1(l1l6, gauss);
    3231 
    3232                 vzpattyn_input->GetParameterValue(&w, gauss);
    3233                 vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
    3234 
    3235                 BedNormal(&bed_normal[0],xyz_list_tria);
    3236                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    3237                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3238                 friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
    3239 
    3240                 for(i=0;i<NUMVERTICES2D;i++){
    3241                         pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*l1l6[i];
    3242                         pe->values[i*NDOF4+1]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[1]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[1])*l1l6[i];
    3243                         pe->values[i*NDOF4+2]+=Jdet2d*gauss->weight*2*viscosity*(dw[0]*bed_normal[0]+dw[1]*bed_normal[1]+dw[2]*bed_normal[2])*l1l6[i];
    3244                 }
    3245         }
    3246 
    3247         /*Clean up and return*/
    3248         delete gauss;
    3249         return pe;
    3250 }
    3251 /*}}}*/
    3252 /*FUNCTION Penta::CreatePVectorDiagnosticHoriz{{{1*/
    3253 ElementVector* Penta::CreatePVectorDiagnosticHoriz(void){
    3254 
    3255         int approximation;
    3256         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3257 
    3258         switch(approximation){
    3259                 case MacAyealApproximationEnum:
    3260                         return CreatePVectorDiagnosticMacAyeal();
    3261                 case PattynApproximationEnum:
    3262                         return CreatePVectorDiagnosticPattyn();
    3263                 case HutterApproximationEnum:
    3264                         return NULL;
    3265                 case NoneApproximationEnum:
    3266                         return NULL;
    3267                 case StokesApproximationEnum:
    3268                         return CreatePVectorDiagnosticStokes();
    3269                 case MacAyealPattynApproximationEnum:
    3270                         return CreatePVectorDiagnosticMacAyealPattyn();
    3271                 case PattynStokesApproximationEnum:
    3272                         return CreatePVectorDiagnosticPattynStokes();
    3273                 default:
    3274                         ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
    3275         }
    3276 }
    3277 /*}}}*/
    3278 /*FUNCTION Penta::CreatePVectorDiagnosticMacAyealPattyn{{{1*/
    3279 ElementVector* Penta::CreatePVectorDiagnosticMacAyealPattyn(void){
    3280 
    3281         /*compute all load vectors for this element*/
    3282         ElementVector* pe1=CreatePVectorDiagnosticMacAyeal();
    3283         ElementVector* pe2=CreatePVectorDiagnosticPattyn();
    3284         ElementVector* pe =new ElementVector(pe1,pe2);
    3285 
    3286         /*clean-up and return*/
    3287         delete pe1;
    3288         delete pe2;
    3289         return pe;
    3290 }
    3291 /*}}}*/
    3292 /*FUNCTION Penta::CreatePVectorDiagnosticPattynStokes{{{1*/
    3293 ElementVector* Penta::CreatePVectorDiagnosticPattynStokes(void){
    3294 
    3295         /*compute all load vectors for this element*/
    3296         ElementVector* pe1=CreatePVectorDiagnosticPattyn();
    3297         ElementVector* pe2=CreatePVectorDiagnosticStokes();
    3298         ElementVector* pe3=CreatePVectorCouplingPattynStokes();
    3299         ElementVector* pe =new ElementVector(pe1,pe2,pe3);
    3300 
    3301         /*clean-up and return*/
    3302         delete pe1;
    3303         delete pe2;
    3304         delete pe3;
    3305         return pe;
    3306 }
    3307 /*}}}*/
    3308 /*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
    3309 ElementVector* Penta::CreatePVectorDiagnosticHutter(void){
    3310 
    3311         /*Constants*/
    3312         const int numdofs=NDOF2*NUMVERTICES;
    3313 
    3314         /*Intermediaries*/
    3315         int          i,j,k,ig;
    3316         int          node0,node1;
    3317         int          connectivity[2];
    3318         double       Jdet;
    3319         double       xyz_list[NUMVERTICES][3];
    3320         double       xyz_list_segment[2][3];
    3321         double       z_list[NUMVERTICES];
    3322         double       z_segment[2],slope[2];
    3323         double       slope2,constant_part;
    3324         double       rho_ice,gravity,n,B;
    3325         double       ub,vb,z_g,surface,thickness;
    3326         GaussPenta*  gauss=NULL;
    3327 
    3328         /*Initialize Element vector and return if necessary*/
    3329         if(IsOnWater()) return NULL;
    3330         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3331 
    3332         /*Retrieve all inputs and parameters*/
    3333         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3334         rho_ice=matpar->GetRhoIce();
    3335         gravity=matpar->GetG();
    3336         n=matice->GetN();
    3337         B=matice->GetB();
    3338         Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
    3339         Input* surface_input=inputs->GetInput(SurfaceEnum);      ISSMASSERT(surface_input);
    3340         Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
    3341         Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
    3342         for(i=0;i<NUMVERTICES;i++)z_list[i]=xyz_list[i][2];
    3343 
    3344         /*Loop on the three segments*/
    3345         for(i=0;i<3;i++){
    3346                 node0=i;
    3347                 node1=i+3;
    3348 
    3349                 for(j=0;j<3;j++){
    3350                         xyz_list_segment[0][j]=xyz_list[node0][j];
    3351                         xyz_list_segment[1][j]=xyz_list[node1][j];
    3352                 }
    3353 
    3354                 connectivity[0]=nodes[node0]->GetConnectivity();
    3355                 connectivity[1]=nodes[node1]->GetConnectivity();
    3356 
    3357                 /*Loop on the Gauss points: */
    3358                 gauss=new GaussPenta(node0,node1,3);
    3359                 for(ig=gauss->begin();ig<gauss->end();ig++){
    3360                         gauss->GaussPoint(ig);
    3361 
    3362                         slopex_input->GetParameterValue(&slope[0],gauss);
    3363                         slopey_input->GetParameterValue(&slope[1],gauss);
    3364                         surface_input->GetParameterValue(&surface,gauss);
    3365                         thickness_input->GetParameterValue(&thickness,gauss);
    3366 
    3367                         slope2=pow(slope[0],2)+pow(slope[1],2);
    3368                         constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
    3369 
    3370                         PentaRef::GetParameterValue(&z_g,&z_list[0],gauss);
    3371                         GetSegmentJacobianDeterminant(&Jdet,&xyz_list_segment[0][0],gauss);
    3372 
    3373                         if (IsOnSurface()){
    3374                                 for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight/(double)connectivity[1];
    3375                         }
    3376                         else{//connectivity is too large, should take only half on it
    3377                                 for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight*2/(double)connectivity[1];
    3378                         }
    3379                 }
    3380                 delete gauss;
    3381 
    3382                 //Deal with lower surface
    3383                 if (IsOnBed()){
    3384                         constant_part=-1.58*pow((double)10.0,-(double)10.0)*rho_ice*gravity*thickness;
    3385                         ub=constant_part*slope[0];
    3386                         vb=constant_part*slope[1];
    3387 
    3388                         pe->values[2*node0]+=ub/(double)connectivity[0];
    3389                         pe->values[2*node0+1]+=vb/(double)connectivity[0];
    3390                 }
    3391         }
    3392 
    3393         /*Clean up and return*/
    3394         return pe;
    3395 }
    3396 /*}}}*/
    3397 /*FUNCTION Penta::CreatePVectorDiagnosticMacAyeal{{{1*/
    3398 ElementVector* Penta::CreatePVectorDiagnosticMacAyeal(void){
    3399 
    3400         if (!IsOnBed() || IsOnWater()) return NULL;
    3401 
    3402         /*Call Tria function*/
    3403         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3404         ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
    3405         delete tria->matice; delete tria;
    3406 
    3407         /*Clean up and return*/
    3408         return pe;
    3409 }
    3410 /*}}}*/
    3411 /*FUNCTION Penta::CreatePVectorDiagnosticPattyn{{{1*/
    3412 ElementVector* Penta::CreatePVectorDiagnosticPattyn(void){
    3413 
    3414         /*Constants*/
    3415         const int    numdof=NDOF2*NUMVERTICES;
    3416 
    3417         /*Intermediaries*/
    3418         int         i,j,ig;
    3419         double      Jdet;
    3420         double      slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
    3421         double      driving_stress_baseline,thickness;
    3422         double      xyz_list[NUMVERTICES][3];
    3423         double      l1l6[6];
    3424         GaussPenta  *gauss=NULL;
    3425 
    3426         /*Initialize Element vector and return if necessary*/
    3427         if(IsOnWater()) return NULL;
    3428         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
    3429 
    3430         /*Retrieve all inputs and parameters*/
    3431         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3432         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    3433         Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
    3434 
    3435         /* Start  looping on the number of gaussian points: */
    3436         gauss=new GaussPenta(2,3);
    3437         for (ig=gauss->begin();ig<gauss->end();ig++){
    3438 
    3439                 gauss->GaussPoint(ig);
    3440 
    3441                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    3442                 GetNodalFunctionsP1(l1l6, gauss);
    3443 
    3444                 thickness_input->GetParameterValue(&thickness, gauss);
    3445                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    3446 
    3447                 driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
    3448 
    3449                 for(i=0;i<NUMVERTICES;i++) for(j=0;j<NDOF2;j++) pe->values[i*NDOF2+j]+= -driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l6[i];
    3450         }
    3451 
    3452         /*Clean up and return*/
    3453         delete gauss;
    3454         return pe;
    3455 }
    3456 /*}}}*/
    3457 /*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
    3458 ElementVector* Penta::CreatePVectorDiagnosticStokes(void){
    3459 
    3460         /*compute all load vectors for this element*/
    3461         ElementVector* pe1=CreatePVectorDiagnosticStokesViscous();
    3462         ElementVector* pe2=CreatePVectorDiagnosticStokesShelf();
    3463         ElementVector* pe =new ElementVector(pe1,pe2);
    3464 
    3465         /*clean-up and return*/
    3466         delete pe1;
    3467         delete pe2;
    3468         return pe;
    3469 }
    3470 /*}}}*/
    3471 /*FUNCTION Penta::CreatePVectorDiagnosticStokesViscous {{{1*/
    3472 ElementVector* Penta::CreatePVectorDiagnosticStokesViscous(void){
    3473 
    3474         /*Constants*/
    3475         const int numdofbubble=NDOF4*NUMVERTICES+NDOF3*1;
    3476 
    3477         /*Intermediaries*/
    3478         int        i,j,ig;
    3479         int        approximation;
    3480         double     Jdet,viscosity;
    3481         double     gravity,rho_ice,stokesreconditioning;
    3482         double     xyz_list[NUMVERTICES][3];
    3483         double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    3484         double     l1l7[7]; //for the six nodes and the bubble
    3485         double     B[8][numdofbubble];
    3486         double     B_prime[8][numdofbubble];
    3487         double     B_prime_bubble[8][3];
    3488         double     D[8][8]={0.0};
    3489         double     D_scalar;
    3490         double     Pe_gaussian[numdofbubble]={0.0}; //for the six nodes and the bubble
    3491         double     Ke_temp[numdofbubble][3]={0.0}; //for the six nodes and the bubble
    3492         double     Ke_gaussian[numdofbubble][3];
    3493         GaussPenta *gauss=NULL;
    3494 
    3495         /*Initialize Element vector and return if necessary*/
    3496         if(IsOnWater()) return NULL;
    3497         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3498         if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
    3499         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    3500 
    3501         /*Retrieve all inputs and parameters*/
    3502         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    3503         rho_ice=matpar->GetRhoIce();
    3504         gravity=matpar->GetG();
    3505         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3506         Input* vx_input=inputs->GetInput(VxEnum);   ISSMASSERT(vx_input);
    3507         Input* vy_input=inputs->GetInput(VyEnum);   ISSMASSERT(vy_input);
    3508         Input* vz_input=inputs->GetInput(VzEnum);   ISSMASSERT(vz_input);
    3509 
    3510         /* Start  looping on the number of gaussian points: */
    3511         gauss=new GaussPenta(5,5);
    3512         for (ig=gauss->begin();ig<gauss->end();ig++){
    3513 
    3514                 gauss->GaussPoint(ig);
    3515 
    3516                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    3517                 GetBStokes(&B[0][0],&xyz_list[0][0],gauss);
    3518                 GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss);
    3519                 GetNodalFunctionsMINI(&l1l7[0], gauss);
    3520 
    3521                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    3522                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3523 
    3524                 for(i=0;i<NUMVERTICES+1;i++){
    3525                         Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
    3526                 }
    3527 
    3528                 /*Get bubble part of Bprime */
    3529                 for(i=0;i<8;i++) for(j=0;j<3;j++) B_prime_bubble[i][j]=B_prime[i][j+24];
    3530 
    3531                 D_scalar=gauss->weight*Jdet;
    3532                 for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
    3533                 for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
    3534 
    3535                 TripleMultiply(&B[0][0],8,numdofbubble,1,
    3536                                         &D[0][0],8,8,0,
    3537                                         &B_prime_bubble[0][0],8,3,0,
    3538                                         &Ke_gaussian[0][0],0);
    3539 
    3540                 for(i=0;i<numdofbubble;i++) for(j=0;j<NDOF3;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
    3541         }
    3542 
    3543         /*Condensation*/
    3544         ReduceVectorStokes(pe->values, &Ke_temp[0][0], &Pe_gaussian[0]);
    3545 
    3546         /*Clean up and return*/
    3547         delete gauss;
    3548         return pe;
    3549 }
    3550 /*}}}*/
    3551 /*FUNCTION Penta::CreatePVectorDiagnosticStokesShelf{{{1*/
    3552 ElementVector* Penta::CreatePVectorDiagnosticStokesShelf(void){
    3553 
    3554         /*Intermediaries*/
    3555         int         i,j,ig;
    3556         int         approximation;
    3557         double      gravity,rho_water,bed,water_pressure;
    3558         double          xyz_list_tria[NUMVERTICES2D][3];
    3559         double      xyz_list[NUMVERTICES][3];
    3560         double          bed_normal[3];
    3561         double      l1l6[6]; //for the six nodes of the penta
    3562         double      Jdet2d;
    3563         GaussPenta  *gauss=NULL;
    3564 
    3565         /*Initialize Element vector and return if necessary*/
    3566         if(IsOnWater() || !IsOnBed() || !IsOnShelf()) return NULL;
    3567         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3568         if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
    3569         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    3570 
    3571         /*Retrieve all inputs and parameters*/
    3572         rho_water=matpar->GetRhoWater();
    3573         gravity=matpar->GetG();
    3574         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3575         Input* bed_input=inputs->GetInput(BedEnum); ISSMASSERT(bed_input);
    3576 
    3577         for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
    3578 
    3579         /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    3580         gauss=new GaussPenta(0,1,2,2);
    3581         for(ig=gauss->begin();ig<gauss->end();ig++){
    3582 
    3583                 gauss->GaussPoint(ig);
    3584 
    3585                 GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
    3586                 GetNodalFunctionsP1(l1l6, gauss);
    3587 
    3588                 bed_input->GetParameterValue(&bed, gauss);
    3589                 BedNormal(&bed_normal[0],xyz_list_tria);
    3590                 water_pressure=gravity*rho_water*bed;
    3591 
    3592                 for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) pe->values[i*NDOF4+j]+=water_pressure*gauss->weight*Jdet2d*l1l6[i]*bed_normal[j];
    3593         }
    3594 
    3595         /*Clean up and return*/
    3596         delete gauss;
    3597         return pe;
    3598 }
    3599 /*}}}*/
    3600 /*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
    3601 ElementVector* Penta::CreatePVectorAdjointStokes(void){
    3602 
    3603         if (!IsOnSurface() || IsOnWater()) return NULL;
    3604 
    3605         /*Call Tria function*/
    3606         Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    3607         ElementVector* pe=tria->CreatePVectorAdjointStokes();
    3608         delete tria->matice; delete tria;
    3609 
    3610         /*clean up and return*/
    3611         return pe;
    3612 }
    3613 /*}}}*/
    3614 /*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
    3615 ElementVector* Penta::CreatePVectorDiagnosticVert(void){
    3616 
    3617         /*compute all load vectors for this element*/
    3618         ElementVector* pe1=CreatePVectorDiagnosticVertVolume();
    3619         ElementVector* pe2=CreatePVectorDiagnosticVertBase();
    3620         ElementVector* pe =new ElementVector(pe1,pe2);
    3621 
    3622         /*clean-up and return*/
    3623         delete pe1;
    3624         delete pe2;
    3625         return pe;
    3626 }
    3627 /*}}}*/
    3628 /*FUNCTION Penta::CreatePVectorDiagnosticVertVolume {{{1*/
    3629 ElementVector* Penta::CreatePVectorDiagnosticVertVolume(void){
    3630 
    3631         /*Constants*/
    3632         const int  numdof=NDOF1*NUMVERTICES;
    3633 
    3634         /*Intermediaries*/
    3635         int        i,ig;
    3636         int        approximation;
    3637         double     Jdet;
    3638         double     xyz_list[NUMVERTICES][3];
    3639         double     dudx,dvdy,dwdz;
    3640         double     du[3],dv[3],dw[3];
    3641         double     l1l6[6];
    3642         GaussPenta *gauss=NULL;
    3643 
    3644         /*Initialize Element vector and return if necessary*/
    3645         if(IsOnWater()) return NULL;
    3646         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3647 
    3648         /*Retrieve all inputs and parameters*/
    3649         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3650         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3651         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    3652         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    3653         Input* vzstokes_input=NULL;
    3654         if(approximation==PattynStokesApproximationEnum){
    3655                 vzstokes_input=inputs->GetInput(VzStokesEnum); ISSMASSERT(vzstokes_input);
    3656         }
    3657 
    3658         /* Start  looping on the number of gaussian points: */
    3659         gauss=new GaussPenta(2,2);
    3660         for (ig=gauss->begin();ig<gauss->end();ig++){
    3661 
    3662                 gauss->GaussPoint(ig);
    3663 
    3664                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    3665                 GetNodalFunctionsP1(l1l6, gauss);
    3666 
    3667                 vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss);
    3668                 vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss);
    3669                 if(approximation==PattynStokesApproximationEnum){
    3670                         vzstokes_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
    3671                         dwdz=dw[2];
    3672                 }
    3673                 else dwdz=0;
    3674                 dudx=du[0];
    3675                 dvdy=dv[1];
    3676 
    3677                 for (i=0;i<numdof;i++) pe->values[i] += (dudx+dvdy+dwdz)*Jdet*gauss->weight*l1l6[i];
    3678         }
    3679 
    3680         /*Clean up and return*/
    3681         delete gauss;
    3682         return pe;
    3683 }
    3684 /*}}}*/
    3685 /*FUNCTION Penta::CreatePVectorDiagnosticVertBase {{{1*/
    3686 ElementVector* Penta::CreatePVectorDiagnosticVertBase(void){
    3687 
    3688         if (!IsOnBed() || IsOnWater()) return NULL;
    3689 
    3690         /*Call Tria function*/
    3691         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3692         ElementVector* pe=tria->CreatePVectorDiagnosticBaseVert();
    3693         delete tria->matice; delete tria;
    3694 
    3695         /*Clean up and return*/
    3696         return pe;
    3697 }
    3698 /*}}}*/
    3699 /*FUNCTION Penta::CreatePVectorMelting {{{1*/
    3700 ElementVector* Penta::CreatePVectorMelting(void){
    3701         return NULL;
    3702 }
    3703 /*}}}*/
    3704 /*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
    3705 ElementVector* Penta::CreatePVectorPrognostic(void){
    3706 
    3707         if (!IsOnBed() || IsOnWater()) return NULL;
    3708 
    3709         /*Depth Averaging Vx and Vy*/
    3710         this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
    3711         this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
    3712 
    3713         /*Call Tria function*/
    3714         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3715         ElementVector* pe=tria->CreatePVectorPrognostic();
    3716         delete tria->matice; delete tria;
    3717 
    3718         /*Delete Vx and Vy averaged*/
    3719         this->inputs->DeleteInput(VxAverageEnum);
    3720         this->inputs->DeleteInput(VyAverageEnum);
    3721 
    3722         /*Clean up and return*/
    3723         return pe;
    3724 }
    3725 /*}}}*/
    3726 /*FUNCTION Penta::CreatePVectorSlope {{{1*/
    3727 ElementVector* Penta::CreatePVectorSlope(void){
    3728 
    3729         if (!IsOnBed() || IsOnWater()) return NULL;
    3730 
    3731         /*Call Tria function*/
    3732         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3733         ElementVector* pe=tria->CreatePVectorSlope();
    3734         delete tria->matice; delete tria;
    3735 
    3736         /*clean up and return*/
    3737         return pe;
    3738 }
    3739 /*}}}*/
    3740 /*FUNCTION Penta::CreatePVectorThermal {{{1*/
    3741 ElementVector* Penta::CreatePVectorThermal(void){
    3742 
    3743         /*compute all load vectors for this element*/
    3744         ElementVector* pe1=CreatePVectorThermalVolume();
    3745         ElementVector* pe2=CreatePVectorThermalSheet();
    3746         ElementVector* pe3=CreatePVectorThermalShelf();
    3747         ElementVector* pe =new ElementVector(pe1,pe2,pe3);
    3748 
    3749         /*clean-up and return*/
    3750         delete pe1;
    3751         delete pe2;
    3752         delete pe3;
    3753         return pe;
    3754 }
    3755 /*}}}*/
    3756 /*FUNCTION Penta::CreatePVectorThermalVolume {{{1*/
    3757 ElementVector* Penta::CreatePVectorThermalVolume(void){
    3758 
    3759         /*Constants*/
    3760         const int  numdof=NUMVERTICES*NDOF1;
    3761 
    3762         /*Intermediaries*/
    3763         int    i,j,ig,found=0;
    3764         int    friction_type,artdiff;
    3765         double Jdet,phi,dt;
    3766         double rho_ice,heatcapacity;
    3767         double thermalconductivity;
    3768         double viscosity,temperature;
    3769         double tau_parameter,diameter;
    3770         double u,v,w;
    3771         double scalar_def,scalar_transient;
    3772         double temperature_list[NUMVERTICES];
    3773         double xyz_list[NUMVERTICES][3];
    3774         double L[numdof];
    3775         double dh1dh6[3][6];
    3776         double epsilon[6];
    3777         GaussPenta *gauss=NULL;
    3778 
    3779         /*Initialize Element vector and return if necessary*/
    3780         if(IsOnWater()) return NULL;
    3781         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3782 
    3783         /*Retrieve all inputs and parameters*/
    3784         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3785         rho_ice=matpar->GetRhoIce();
    3786         heatcapacity=matpar->GetHeatCapacity();
    3787         thermalconductivity=matpar->GetThermalConductivity();
    3788         this->inputs->GetParameterValue(&dt,DtEnum);
    3789         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    3790         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    3791         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    3792         Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
    3793         Input* temperature_input=NULL;
    3794         if (dt) temperature_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(inputs);
    3795         if (artdiff==2) diameter=MinEdgeLength(xyz_list);
    3796 
    3797         /* Start  looping on the number of gaussian points: */
    3798         gauss=new GaussPenta(2,3);
    3799         for (ig=gauss->begin();ig<gauss->end();ig++){
    3800 
    3801                 gauss->GaussPoint(ig);
    3802 
    3803                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
    3804                 GetNodalFunctionsP1(&L[0], gauss);
    3805 
    3806                 this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
    3807                 matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3808                 GetPhi(&phi, &epsilon[0], viscosity);
    3809 
    3810                 scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
    3811                 if(dt) scalar_def=scalar_def*dt;
    3812 
    3813                 for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
    3814 
    3815                 /* Build transient now */
    3816                 if(dt){
    3817                         temperature_input->GetParameterValue(&temperature, gauss);
    3818                         scalar_transient=temperature*Jdet*gauss->weight;
    3819                         for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
    3820                 }
    3821 
    3822                 if(artdiff==2){
    3823                         GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
    3824 
    3825                         vx_input->GetParameterValue(&u, gauss);
    3826                         vy_input->GetParameterValue(&v, gauss);
    3827                         vz_input->GetParameterValue(&w, gauss);
    3828 
    3829                         tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
    3830 
    3831                         for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
    3832                         if(dt){
    3833                                 for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
    3834                         }
    3835                 }
    3836         }
    3837 
    3838         /*Clean up and return*/
    3839         delete gauss;
    3840         return pe;
    3841 }
    3842 /*}}}*/
    3843 /*FUNCTION Penta::CreatePVectorThermalShelf {{{1*/
    3844 ElementVector* Penta::CreatePVectorThermalShelf(void){
    3845 
    3846         /* Ice/ocean heat exchange flux on ice shelf base */
    3847         if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
    3848 
    3849         /*Call Tria function*/
    3850         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3851         ElementVector* pe=tria->CreatePVectorThermalShelf();
    3852         delete tria->matice; delete tria;
    3853 
    3854         /*Clean up and return*/
    3855         return pe;
    3856 }
    3857 /*}}}*/
    3858 /*FUNCTION Penta::CreatePVectorThermalSheet {{{1*/
    3859 ElementVector* Penta::CreatePVectorThermalSheet(void){
    3860 
    3861         /* Geothermal flux on ice sheet base and basal friction */
    3862         if (!IsOnBed() || IsOnShelf() || IsOnWater()) return NULL;
    3863 
    3864         /*Call Tria function*/
    3865         Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3866         ElementVector* pe=tria->CreatePVectorThermalSheet();
    3867         delete tria->matice; delete tria;
    3868 
    3869         /*Clean up and return*/
    3870         return pe;
    3871 }
    3872 /*}}}*/
    3873 /*FUNCTION Penta::GetDofList {{{1*/
    3874 void  Penta::GetDofList(int** pdoflist,int approximation_enum,int setenum){
    3875 
    3876         int  i,j,count=0;
    3877         int  numberofdofs=0;
    3878         int* doflist=NULL;
    3879 
    3880         /*First, figure out size of doflist: */
    3881         for(i=0;i<6;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
    3882 
    3883         /*Allocate: */
    3884         doflist=(int*)xmalloc(numberofdofs*sizeof(int));
    3885 
    3886         /*Populate: */
    3887         count=0;
    3888         for(i=0;i<6;i++){
    3889                 nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
    3890                 count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
    3891         }
    3892 
    3893         /*Assign output pointers:*/
    3894         *pdoflist=doflist;
    3895 }
    3896 /*}}}*/
    3897 /*FUNCTION Penta::GetDofList1 {{{1*/
    3898 void  Penta::GetDofList1(int* doflist){
    3899        
    3900         int i;
    3901         for(i=0;i<6;i++) doflist[i]=nodes[i]->GetDofList1();
    3902 
    3903 }
    3904 /*}}}*/
    3905 /*FUNCTION Penta::GetSidList{{{1*/
    3906 void  Penta::GetSidList(int* sidlist){
    3907 
    3908         int i;
    3909         for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
    3910 
    3911 }
    3912 /*}}}*/
    3913 /*FUNCTION Penta::GetElementType {{{1*/
    3914 int Penta::GetElementType(){
    3915 
    3916         /*return PentaRef field*/
    3917         return this->element_type;
    3918 }
    3919 /*}}}*/
    3920 /*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
    3921 void Penta::GetParameterListOnVertices(double* pvalue,int enumtype){
    3922 
    3923         /*Intermediaries*/
    3924         double     value[NUMVERTICES];
    3925         GaussPenta *gauss              = NULL;
    3926 
    3927         /*Recover input*/
    3928         Input* input=inputs->GetInput(enumtype);
    3929         if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
    3930 
    3931         /*Checks in debugging mode*/
    3932         ISSMASSERT(pvalue);
    3933 
    3934         /* Start looping on the number of vertices: */
    3935         gauss=new GaussPenta();
    3936         for (int iv=0;iv<NUMVERTICES;iv++){
    3937                 gauss->GaussVertex(iv);
    3938                 input->GetParameterValue(&pvalue[iv],gauss);
    3939         }
    3940 
    3941         /*clean-up*/
    3942         delete gauss;
    3943 }
    3944 /*}}}*/
    3945 /*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
    3946 void Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
    3947 
    3948         /*Intermediaries*/
    3949         double     value[NUMVERTICES];
    3950         GaussPenta *gauss              = NULL;
    3951 
    3952         /*Recover input*/
    3953         Input* input=inputs->GetInput(enumtype);
    3954 
    3955         /*Checks in debugging mode*/
    3956         ISSMASSERT(pvalue);
    3957 
    3958         /* Start looping on the number of vertices: */
    3959         if (input){
    3960                 gauss=new GaussPenta();
    3961                 for (int iv=0;iv<NUMVERTICES;iv++){
    3962                         gauss->GaussVertex(iv);
    3963                         input->GetParameterValue(&pvalue[iv],gauss);
    3964                 }
    3965         }
    3966         else{
    3967                 for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
    3968         }
    3969 
    3970         /*clean-up*/
    3971         delete gauss;
    3972 }
    3973 /*}}}*/
    3974 /*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
    3975 void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
    3976 
    3977         Input* input=inputs->GetInput(enumtype);
    3978         if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
    3979 
    3980         GaussPenta* gauss=new GaussPenta();
    3981         gauss->GaussVertex(this->GetNodeIndex(node));
    3982 
    3983         input->GetParameterValue(pvalue,gauss);
    3984         delete gauss;
    3985 }
    3986 /*}}}*/
    3987 /*FUNCTION Penta::GetPhi {{{1*/
    3988 void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
    3989         /*Compute deformational heating from epsilon and viscosity */
    3990 
    3991         double epsilon_matrix[3][3];
    3992         double epsilon_eff;
    3993         double epsilon_sqr[3][3];
    3994 
    3995         /* Build epsilon matrix */
    3996         epsilon_matrix[0][0]=*(epsilon+0);
    3997         epsilon_matrix[1][0]=*(epsilon+3);
    3998         epsilon_matrix[2][0]=*(epsilon+4);
    3999         epsilon_matrix[0][1]=*(epsilon+3);
    4000         epsilon_matrix[1][1]=*(epsilon+1);
    4001         epsilon_matrix[2][1]=*(epsilon+5);
    4002         epsilon_matrix[0][2]=*(epsilon+4);
    4003         epsilon_matrix[1][2]=*(epsilon+5);
    4004         epsilon_matrix[2][2]=*(epsilon+2);
    4005 
    4006         /* Effective value of epsilon_matrix */
    4007         epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
    4008         epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
    4009         epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
    4010         epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
    4011         epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
    4012         epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
    4013         epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
    4014         epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
    4015         epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
    4016         epsilon_eff=1/pow(2,0.5)*pow((epsilon_sqr[0][0]+epsilon_sqr[0][1]+ epsilon_sqr[0][2]+ epsilon_sqr[1][0]+ epsilon_sqr[1][1]+ epsilon_sqr[1][2]+ epsilon_sqr[2][0]+ epsilon_sqr[2][1]+ epsilon_sqr[2][2]),0.5);
    4017 
    4018         /*Phi = Tr(sigma * eps)
    4019          *    = Tr(sigma'* eps)
    4020          *    = 2 * eps_eff * sigma'_eff
    4021          *    = 4 * eps_eff ^2*/
    4022         *phi=4*pow(epsilon_eff,2.0)*viscosity;
    4023 }
    4024 /*}}}*/
    4025 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
    4026 void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
    4027 
    4028         const int    numdof=NDOF2*NUMVERTICES;
    4029 
    4030         int          i;
    4031         int          approximation;
    4032         int*         doflist=NULL;
    4033         double       vx,vy;
    4034         double       values[numdof];
    4035         GaussPenta*  gauss;
    4036 
    4037         /*Get approximation enum and dof list: */
    4038         inputs->GetParameterValue(&approximation,ApproximationEnum);
    4039         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    4040         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    4041 
    4042         /*If the element is a coupling, do nothing: every grid is also on an other elements
    4043          * (as coupling is between MacAyeal and Pattyn) so the other element will take care of it*/
    4044         GetDofList(&doflist,approximation,GsetEnum);
    4045 
    4046         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4047         /*P1 element only for now*/
    4048         gauss=new GaussPenta();
    4049         for(i=0;i<NUMVERTICES;i++){
    4050 
    4051                 /*Recover vx and vy*/
    4052                 gauss->GaussVertex(i);
    4053                 vx_input->GetParameterValue(&vx,gauss);
    4054                 vy_input->GetParameterValue(&vy,gauss);
    4055                 values[i*NDOF2+0]=vx;
    4056                 values[i*NDOF2+1]=vy;
    4057         }
    4058 
    4059         /*Add value to global vector*/
    4060         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4061 
    4062         /*Free ressources:*/
    4063         delete gauss;
    4064         xfree((void**)&doflist);
    4065 }
    4066 /*}}}*/
    4067 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
    4068 void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
    4069 
    4070         const int    numdof=NDOF2*NUMVERTICES;
    4071 
    4072         int          i;
    4073         int*         doflist=NULL;
    4074         double       vx,vy;
    4075         double       values[numdof];
    4076         GaussPenta*  gauss=NULL;
    4077 
    4078         /*Get dof list: */
    4079         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4080         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    4081         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    4082 
    4083         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4084         /*P1 element only for now*/
    4085         gauss=new GaussPenta();
    4086         for(i=0;i<NUMVERTICES;i++){
    4087                 /*Recover vx and vy*/
    4088                 gauss->GaussVertex(i);
    4089                 vx_input->GetParameterValue(&vx,gauss);
    4090                 vy_input->GetParameterValue(&vy,gauss);
    4091                 values[i*NDOF2+0]=vx;
    4092                 values[i*NDOF2+1]=vy;
    4093         }
    4094 
    4095         /*Add value to global vector*/
    4096         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4097 
    4098         /*Free ressources:*/
    4099         delete gauss;
    4100         xfree((void**)&doflist);
    4101 }
    4102 /*}}}*/
    4103 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
    4104 void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
    4105 
    4106         const int    numdof=NDOF1*NUMVERTICES;
    4107 
    4108         int          i;
    4109         int*         doflist=NULL;
    4110         double       vz;
    4111         double       values[numdof];
    4112         GaussPenta*  gauss=NULL;
    4113 
    4114         /*Get dof list: */
    4115         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4116         Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
    4117 
    4118         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4119         /*P1 element only for now*/
    4120         gauss=new GaussPenta();
    4121         for(i=0;i<NUMVERTICES;i++){
    4122                 /*Recover vz */
    4123                 gauss->GaussVertex(i);
    4124                 vz_input->GetParameterValue(&vz,gauss);
    4125                 values[i]=vz;
    4126         }
    4127 
    4128         /*Add value to global vector*/
    4129         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4130 
    4131         /*Free ressources:*/
    4132         delete gauss;
    4133         xfree((void**)&doflist);
    4134 }
    4135 /*}}}*/
    4136 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
    4137 void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
    4138 
    4139         const int    numdof=NDOF4*NUMVERTICES;
    4140 
    4141         int          i;
    4142         int*         doflist=NULL;
    4143         double       vx,vy,vz,p;
    4144         double       stokesreconditioning;
    4145         double       values[numdof];
    4146         GaussPenta   *gauss;
    4147 
    4148         /*Get dof list: */
    4149         GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
    4150         Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
    4151         Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
    4152         Input* vz_input=inputs->GetInput(VzEnum);       ISSMASSERT(vz_input);
    4153         Input* p_input =inputs->GetInput(PressureEnum); ISSMASSERT(p_input);
    4154 
    4155         /*Recondition pressure: */
    4156         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    4157 
    4158         /*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
    4159         /*P1 element only for now*/
    4160         gauss=new GaussPenta();
    4161         for(i=0;i<NUMVERTICES;i++){
    4162                 gauss->GaussVertex(i);
    4163                 vx_input->GetParameterValue(&vx,gauss);
    4164                 vy_input->GetParameterValue(&vy,gauss);
    4165                 vz_input->GetParameterValue(&vz,gauss);
    4166                 p_input ->GetParameterValue(&p ,gauss);
    4167                 values[i*NDOF4+0]=vx;
    4168                 values[i*NDOF4+1]=vy;
    4169                 values[i*NDOF4+2]=vz;
    4170                 values[i*NDOF4+3]=p/stokesreconditioning;
    4171         }
    4172 
    4173         /*Add value to global vector*/
    4174         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4175 
    4176         /*Free ressources:*/
    4177         delete gauss;
    4178         xfree((void**)&doflist);
    4179 }
    4180 /*}}}*/
    4181 /*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
    4182 void  Penta::GetSolutionFromInputsThermal(Vec solution){
    4183 
    4184         const int    numdof=NDOF1*NUMVERTICES;
    4185 
    4186         int          i;
    4187         int*         doflist=NULL;
    4188         double       values[numdof];
    4189         double       temp;
    4190         GaussPenta   *gauss=NULL;
    4191 
    4192         /*Get dof list: */
    4193         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4194         Input* t_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(t_input);
    4195 
    4196         gauss=new GaussPenta();
    4197         for(i=0;i<NUMVERTICES;i++){
    4198                 /*Recover temperature*/
    4199                 gauss->GaussVertex(i);
    4200                 t_input->GetParameterValue(&temp,gauss);
    4201                 values[i]=temp;
    4202         }
    4203 
    4204         /*Add value to global vector*/
    4205         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4206        
    4207         /*Free ressources:*/
    4208         delete gauss;
    4209         xfree((void**)&doflist);
    4210 }
    4211 /*}}}*/
    4212 /*FUNCTION Penta::GetStabilizationParameter {{{1*/
    4213 double Penta::GetStabilizationParameter(double u, double v, double w, double diameter, double rho_ice, double heatcapacity, double thermalconductivity){
    4214         /*Compute stabilization parameter*/
    4215 
    4216         double normu;
    4217         double tau_parameter;
    4218 
    4219         normu=pow(pow(u,2)+pow(v,2)+pow(w,2),0.5);
    4220         if(normu*diameter/(3*2*thermalconductivity/(rho_ice*heatcapacity))<1){
    4221                 tau_parameter=pow(diameter,2)/(3*2*2*thermalconductivity/(rho_ice*heatcapacity));
    4222         }
    4223         else tau_parameter=diameter/(2*normu);
    4224 
    4225         return tau_parameter;
    4226 }
    4227 /*}}}*/
    4228 /*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
    4229 void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input){
    4230         /*Compute the 3d Blatter/PattynStrain Rate (5 components):
    4231          *
    4232          * epsilon=[exx eyy exy exz eyz]
    4233          *
    4234          * with exz=1/2 du/dz
    4235          *      eyz=1/2 dv/dz
    4236          *
    4237          * the contribution of vz is neglected
    4238          */
    4239 
    4240         int i;
    4241         double epsilonvx[5];
    4242         double epsilonvy[5];
    4243 
    4244         /*Check that both inputs have been found*/
    4245         if (!vx_input || !vy_input){
    4246                 ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
    4247         }
    4248 
    4249         /*Get strain rate assuming that epsilon has been allocated*/
    4250         vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
    4251         vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
    4252 
    4253         /*Sum all contributions*/
    4254         for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
    4255 }
    4256 /*}}}*/
    4257 /*FUNCTION Penta::GetStrainRate3d{{{1*/
    4258 void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
    4259         /*Compute the 3d Strain Rate (6 components):
    4260          *
    4261          * epsilon=[exx eyy ezz exy exz eyz]
    4262          */
    4263 
    4264         int i;
    4265         double epsilonvx[6];
    4266         double epsilonvy[6];
    4267         double epsilonvz[6];
    4268 
    4269         /*Check that both inputs have been found*/
    4270         if (!vx_input || !vy_input || !vz_input){
    4271                 ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
    4272         }
    4273 
    4274         /*Get strain rate assuming that epsilon has been allocated*/
    4275         vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
    4276         vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
    4277         vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
    4278 
    4279         /*Sum all contributions*/
    4280         for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
    4281 }
    4282 /*}}}*/
    4283 /*FUNCTION Penta::GetBasalElement{{{1*/
    4284 Penta* Penta::GetBasalElement(void){
    4285 
    4286         /*Output*/
    4287         Penta* penta=NULL;
    4288 
    4289         /*Go through all elements till the bed is reached*/
    4290         penta=this;
    4291         for(;;){
    4292                 /*Stop if we have reached the surface, else, take lower penta*/
    4293                 if (penta->IsOnBed()) break;
    4294 
    4295                 /* get lower Penta*/
    4296                 penta=penta->GetLowerElement();
    4297                 ISSMASSERT(penta->Id()!=this->id);
    4298         }
    4299 
    4300         /*return output*/
    4301         return penta;
    4302 }
    4303 /*}}}*/
    4304 /*FUNCTION Penta::GetLowerElement{{{1*/
    4305 Penta* Penta::GetLowerElement(void){
    4306 
    4307         Penta* upper_penta=NULL;
    4308 
    4309         upper_penta=(Penta*)neighbors[0]; //first one (0) under, second one (1) above
    4310        
    4311         return upper_penta;
    4312 }
    4313 /*}}}*/
    4314 /*FUNCTION Penta::GetUpperElement{{{1*/
    4315 Penta* Penta::GetUpperElement(void){
    4316 
    4317         Penta* upper_penta=NULL;
    4318        
    4319         upper_penta=(Penta*)neighbors[1]; //first one under, second one above
    4320 
    4321         return upper_penta;
    4322 }
    4323 /*}}}*/
    4324 /*FUNCTION Penta::GetZcoord {{{1*/
    4325 double Penta::GetZcoord(GaussPenta* gauss){
    4326 
    4327         int    i;
    4328         double z;
    4329         double xyz_list[NUMVERTICES][3];
    4330         double z_list[NUMVERTICES];
    4331 
    4332         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4333         for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[i][2];
    4334         PentaRef::GetParameterValue(&z,z_list,gauss);
    4335 
    4336         return z;
    4337 }
    4338 /*}}}*/
    4339 /*FUNCTION Penta::GradjB {{{1*/
    4340 void  Penta::GradjB(Vec gradient){
    4341 
    4342         int              i;
    4343         int              approximation;
    4344         Tria*            tria           =NULL;
    4345         TriaVertexInput* triavertexinput=NULL;
    4346 
    4347         /*If on water, skip: */
    4348         if(IsOnWater())return;
    4349         inputs->GetParameterValue(&approximation,ApproximationEnum);
    4350 
    4351         if (approximation==MacAyealApproximationEnum){
    4352                 /*Bail out element if MacAyeal (2d) and not on bed*/
    4353                 if (!IsOnBed()) return;
    4354 
    4355                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    4356                  * and compute gardj*/
    4357 
    4358                 /*Depth Average B*/
    4359                 this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
    4360 
    4361                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    4362                 tria->GradjB(gradient);
    4363                 delete tria->matice; delete tria;
    4364 
    4365                 /*delete B average*/
    4366                 this->matice->inputs->DeleteInput(RheologyBbarEnum);
    4367         }
    4368         else{
    4369                 /*Gradient is computed on bed only (Bbar)*/
    4370                 if (!IsOnBed()) return;
    4371 
    4372                 /*Depth Average B*/
    4373                 this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
    4374 
    4375                 /*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
    4376                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    4377                 tria->GradjB(gradient);
    4378                 delete tria->matice; delete tria;
    4379 
    4380                 /*delete B average*/
    4381                 this->matice->inputs->DeleteInput(RheologyBbarEnum);
    4382         }
    4383 }
    4384 /*}}}*/
    4385 /*FUNCTION Penta::GradjDrag {{{1*/
    4386 void  Penta::GradjDrag(Vec gradient){
    4387 
    4388         int              i,approximation;
    4389         double           temp_gradient[6]={0,0,0,0,0,0};
    4390         Tria*            tria=NULL;
    4391         TriaVertexInput* triavertexinput=NULL;
    4392 
    4393         /*retrieve inputs :*/
    4394         inputs->GetParameterValue(&approximation,ApproximationEnum);
    4395 
    4396         /*If on water, on shelf or not on bed, skip: */
    4397         if(IsOnWater()|| IsOnShelf() || !IsOnBed())return;
    4398 
    4399         if (approximation==MacAyealApproximationEnum || approximation==PattynApproximationEnum){
    4400                 /*MacAyeal or Pattyn*/
    4401                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4402                 tria->GradjDrag(gradient);
    4403                 delete tria->matice; delete tria;
    4404         }
    4405         else if (approximation==StokesApproximationEnum){
    4406                 /*Stokes*/
    4407                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4408                 tria->GradjDragStokes(gradient);
    4409                 delete tria->matice; delete tria;
    4410         }
    4411         else if (approximation==NoneApproximationEnum){
    4412                 return;
    4413         }
    4414         else ISSMERROR("approximation %s not supported yet",EnumToString(approximation));
    4415 }
    4416 /*}}}*/
    4417 /*FUNCTION Penta::InputExtrude {{{1*/
    4418 void  Penta::InputExtrude(int enum_type,int object_type){
    4419 
    4420         Penta *penta          = NULL;
    4421         Input *original_input = NULL;
    4422 
    4423         /*Are we on the base, not on the surface?:*/
    4424         if(IsOnBed()){
    4425                 /*OK, we are on bed. we will follow the steps:
    4426                  * 1: find input and extrude it.
    4427                  * 2: follow the upper element until we reach the surface
    4428                  * 3: for each element, we will add a copy of the extruded input*/
    4429 
    4430                 /*Step1: Extrude the original input: */
    4431                 if (object_type==ElementsEnum)
    4432                  original_input=(Input*)this->inputs->GetInput(enum_type);
    4433                 else if (object_type==MaterialsEnum)
    4434                  original_input=(Input*)matice->inputs->GetInput(enum_type);
    4435                 else
    4436                  ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
    4437                 if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumToString(enum_type));
    4438                 original_input->Extrude();
    4439 
    4440                 /*Stop if there is only one layer of element*/
    4441                 if (this->IsOnSurface()) return;
    4442 
    4443                 /*Step 2: this input has been extruded for this element, now follow the upper element*/
    4444                 penta=this;
    4445                 for(;;){
    4446 
    4447                         /* get upper Penta*/
    4448                         penta=penta->GetUpperElement();
    4449                         ISSMASSERT(penta->Id()!=this->id);
    4450 
    4451                         /*Add input of the basal element to penta->inputs*/
    4452                         Input* copy=NULL;
    4453                         copy=(Input*)original_input->copy();
    4454                         if (object_type==ElementsEnum)
    4455                          penta->inputs->AddInput((Input*)copy);
    4456                         else if (object_type==MaterialsEnum)
    4457                          penta->matice->inputs->AddInput((Input*)copy);
    4458                         else
    4459                          ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
    4460 
    4461                         /*Stop if we have reached the surface*/
    4462                         if (penta->IsOnSurface()) break;
    4463                 }
    4464         }
    4465 
    4466         return;
    4467 }
    4468 /*}}}*/
    4469 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
    4470 void  Penta::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
    4471 
    4472         int  approximation;
    4473 
    4474         /*Recover inputs*/
    4475         inputs->GetParameterValue(&approximation,ApproximationEnum);
    4476 
    4477         /*MacAyeal, everything is done by the element on bed*/
    4478         if (approximation==MacAyealApproximationEnum){
    4479                 if (!IsOnBed()){
    4480                         /*Do nothing. Element on bed will take care of it*/
    4481                         return;
    4482                 }
    4483                 else{
    4484                         InputUpdateFromSolutionDiagnosticMacAyeal(solution);
    4485                         return;
    4486                 }
    4487         }
    4488         else if (approximation==PattynApproximationEnum){
    4489                 InputUpdateFromSolutionDiagnosticPattyn(solution);
    4490         }
    4491         else if (approximation==PattynStokesApproximationEnum){
    4492                 InputUpdateFromSolutionDiagnosticPattynStokes(solution);
    4493         }
    4494         else if (approximation==MacAyealStokesApproximationEnum){
    4495                 InputUpdateFromSolutionDiagnosticMacAyealStokes(solution);
    4496         }
    4497         else if (approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
    4498                 InputUpdateFromSolutionDiagnosticStokes(solution);
    4499         }
    4500         else if (approximation==MacAyealPattynApproximationEnum){
    4501                 InputUpdateFromSolutionDiagnosticMacAyealPattyn(solution);
    4502         }
    4503 }
    4504 /*}}}*/
    4505 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyeal {{{1*/
    4506 void  Penta::InputUpdateFromSolutionDiagnosticMacAyeal(double* solution){
    4507 
    4508         const int    numdof=NDOF2*NUMVERTICES;
    4509 
    4510         int     i,dummy;
    4511         double  rho_ice,g;
    4512         double  values[numdof];
    4513         double  vx[NUMVERTICES];
    4514         double  vy[NUMVERTICES];
    4515         double  vz[NUMVERTICES];
    4516         double  vel[NUMVERTICES];
    4517         double  pressure[NUMVERTICES];
    4518         double  surface[NUMVERTICES];
    4519         double  xyz_list[NUMVERTICES][3];
    4520         int    *doflist = NULL;
    4521         double *vz_ptr  = NULL;
    4522         Penta  *penta   = NULL;
    4523 
    4524         /*Get dof list: */
    4525         GetDofList(&doflist,MacAyealApproximationEnum,GsetEnum);
    4526 
    4527         /*Use the dof list to index into the solution vector: */
    4528         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4529 
    4530         /*Ok, we have vx and vy in values, fill in vx and vy arrays and extrude */
    4531         for(i=0;i<3;i++){
    4532                 vx[i]  =values[i*NDOF2+0];
    4533                 vy[i]  =values[i*NDOF2+1];
    4534                 vx[i+3]=vx[i];
    4535                 vy[i+3]=vy[i];
    4536         }
    4537 
    4538         /*Get parameters fro pressure computation*/
    4539         rho_ice=matpar->GetRhoIce();
    4540         g=matpar->GetG();
    4541 
    4542         /*Start looping over all elements above current element and update all inputs*/
    4543         penta=this;
    4544         for(;;){
    4545 
    4546                 /*Get node data: */
    4547                 GetVerticesCoordinates(&xyz_list[0][0],penta->nodes,NUMVERTICES);
    4548 
    4549                 /*Now Compute vel*/
    4550                 Input* vz_input=inputs->GetInput(VzEnum);
    4551                 if (vz_input){
    4552                         if (vz_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
    4553                         vz_input->GetValuesPtr(&vz_ptr,&dummy);
    4554                         for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
    4555                 }
    4556                 else{for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;}
    4557                 for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4558 
    4559                 /*Now compute pressure*/
    4560                 GetParameterListOnVertices(&surface[0],SurfaceEnum);
    4561                 for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
    4562 
    4563                 /*Now, we have to move the previous Vx and Vy inputs  to old
    4564                  * status, otherwise, we'll wipe them off: */
    4565                 penta->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4566                 penta->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4567                 penta->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4568 
    4569                 /*Add vx and vy as inputs to the tria element: */
    4570                 penta->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4571                 penta->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4572                 penta->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    4573                 penta->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4574 
    4575                 /*Stop if we have reached the surface*/
    4576                 if (penta->IsOnSurface()) break;
    4577 
    4578                 /* get upper Penta*/
    4579                 penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
    4580         }
    4581        
    4582         /*Free ressources:*/
    4583         xfree((void**)&doflist);
    4584 }
    4585 /*}}}*/
    4586 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn {{{1*/
    4587 void  Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn(double* solution){
    4588 
    4589         const int    numdof=NDOF2*NUMVERTICES;
    4590         const int    numdof2d=NDOF2*NUMVERTICES2D;
    4591 
    4592         int     i,dummy;
    4593         double  rho_ice,g;
    4594         double  macayeal_values[numdof];
    4595         double  pattyn_values[numdof];
    4596         double  vx[NUMVERTICES];
    4597         double  vy[NUMVERTICES];
    4598         double  vz[NUMVERTICES];
    4599         double  vel[NUMVERTICES];
    4600         double  pressure[NUMVERTICES];
    4601         double  surface[NUMVERTICES];
    4602         double  xyz_list[NUMVERTICES][3];
    4603         int*    doflistp = NULL;
    4604         int*    doflistm = NULL;
    4605         double  *vz_ptr  = NULL;
    4606         Penta   *penta   = NULL;
    4607 
    4608         /*OK, we have to add results of this element for pattyn
    4609          * and results from the penta at base for macayeal. Now recover results*/
    4610         penta=GetBasalElement();
    4611 
    4612         /*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
    4613         GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
    4614         penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
    4615 
    4616         /*Get node data: */
    4617         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4618 
    4619         /*Use the dof list to index into the solution vector: */
    4620         for(i=0;i<numdof2d;i++){
    4621                 pattyn_values[i]=solution[doflistp[i]];
    4622                 macayeal_values[i]=solution[doflistm[i]];
    4623         }
    4624         for(i=numdof2d;i<numdof;i++){
    4625                 pattyn_values[i]=solution[doflistp[i]];
    4626                 macayeal_values[i]=macayeal_values[i-numdof2d];
    4627         }
    4628 
    4629         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4630         for(i=0;i<NUMVERTICES;i++){
    4631                 vx[i]=macayeal_values[i*NDOF2+0]+pattyn_values[i*NDOF2+0];
    4632                 vy[i]=macayeal_values[i*NDOF2+1]+pattyn_values[i*NDOF2+1];
    4633         }
    4634 
    4635         /*Get Vz*/
    4636         Input* vz_input=inputs->GetInput(VzEnum);
    4637         if (vz_input){
    4638                 if (vz_input->Enum()!=PentaVertexInputEnum){
    4639                         ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
    4640                 }
    4641                 vz_input->GetValuesPtr(&vz_ptr,&dummy);
    4642                 for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
    4643         }
    4644         else{
    4645                 for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
    4646         }
    4647 
    4648         /*Now Compute vel*/
    4649         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4650 
    4651         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
    4652          *so the pressure is just the pressure at the z elevation: */
    4653         rho_ice=matpar->GetRhoIce();
    4654         g=matpar->GetG();
    4655         GetParameterListOnVertices(&surface[0],SurfaceEnum);
    4656         for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
    4657 
    4658         /*Now, we have to move the previous Vx and Vy inputs  to old
    4659          * status, otherwise, we'll wipe them off: */
    4660         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4661         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4662         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4663 
    4664         /*Add vx and vy as inputs to the tria element: */
    4665         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4666         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4667         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    4668         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4669 
    4670         /*Free ressources:*/
    4671         xfree((void**)&doflistp);
    4672         xfree((void**)&doflistm);
    4673 }
    4674 /*}}}*/
    4675 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes {{{1*/
    4676 void  Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes(double* solution){
    4677 
    4678         const int    numdofm=NDOF2*NUMVERTICES;
    4679         const int    numdofs=NDOF4*NUMVERTICES;
    4680         const int    numdof2d=NDOF2*NUMVERTICES2D;
    4681 
    4682         int     i,dummy;
    4683         double  stokesreconditioning;
    4684         double  macayeal_values[numdofm];
    4685         double  stokes_values[numdofs];
    4686         double  vx[NUMVERTICES];
    4687         double  vy[NUMVERTICES];
    4688         double  vz[NUMVERTICES];
    4689         double  vzmacayeal[NUMVERTICES];
    4690         double  vzstokes[NUMVERTICES];
    4691         double  vel[NUMVERTICES];
    4692         double  pressure[NUMVERTICES];
    4693         double  xyz_list[NUMVERTICES][3];
    4694         int*    doflistm        = NULL;
    4695         int*    doflists        = NULL;
    4696         double  *vzmacayeal_ptr = NULL;
    4697         Penta   *penta          = NULL;
    4698 
    4699         /*OK, we have to add results of this element for macayeal
    4700          * and results from the penta at base for macayeal. Now recover results*/
    4701         penta=GetBasalElement();
    4702 
    4703         /*Get dof listof this element (macayeal dofs) and of the penta at base (macayeal dofs): */
    4704         penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
    4705         GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
    4706         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    4707 
    4708         /*Get node data: */
    4709         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4710 
    4711         /*Use the dof list to index into the solution vector: */
    4712         for(i=0;i<numdof2d;i++){
    4713                 macayeal_values[i]=solution[doflistm[i]];
    4714                 macayeal_values[i+numdof2d]=solution[doflistm[i]];
    4715         }
    4716         for(i=0;i<numdofs;i++){
    4717                 stokes_values[i]=solution[doflists[i]];
    4718         }
    4719 
    4720         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4721         for(i=0;i<NUMVERTICES;i++){
    4722                 vx[i]=stokes_values[i*NDOF4+0]+macayeal_values[i*NDOF2+0];
    4723                 vy[i]=stokes_values[i*NDOF4+1]+macayeal_values[i*NDOF2+1];
    4724                 vzstokes[i]=stokes_values[i*NDOF4+2];
    4725                 pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
    4726         }
    4727 
    4728         /*Get Vz*/
    4729         Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
    4730         if (vzmacayeal_input){
    4731                 if (vzmacayeal_input->Enum()!=PentaVertexInputEnum){
    4732                         ISSMERROR("Cannot compute Vel as VzMacAyeal is of type %s",EnumToString(vzmacayeal_input->Enum()));
    4733                 }
    4734                 vzmacayeal_input->GetValuesPtr(&vzmacayeal_ptr,&dummy);
    4735                 for(i=0;i<NUMVERTICES;i++) vzmacayeal[i]=vzmacayeal_ptr[i];
    4736         }
    4737         else{
    4738                 ISSMERROR("Cannot update solution as VzMacAyeal is not present");
    4739         }
    4740 
    4741         /*Now Compute vel*/
    4742         for(i=0;i<NUMVERTICES;i++) {
    4743                 vz[i]=vzmacayeal[i]+vzstokes[i];
    4744                 vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4745         }
    4746 
    4747         /*Now, we have to move the previous Vx and Vy inputs  to old
    4748          * status, otherwise, we'll wipe them off: */
    4749         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4750         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4751         this->inputs->ChangeEnum(VzEnum,VzOldEnum);
    4752         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4753 
    4754         /*Add vx and vy as inputs to the tria element: */
    4755         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4756         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4757         this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
    4758         this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
    4759         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    4760         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4761 
    4762         /*Free ressources:*/
    4763         xfree((void**)&doflistm);
    4764         xfree((void**)&doflists);
    4765 }
    4766 /*}}}*/
    4767 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattyn {{{1*/
    4768 void  Penta::InputUpdateFromSolutionDiagnosticPattyn(double* solution){
    4769        
    4770         const int    numdof=NDOF2*NUMVERTICES;
    4771 
    4772         int    i,dummy;
    4773         double rho_ice,g;
    4774         double values[numdof];
    4775         double vx[NUMVERTICES];
    4776         double vy[NUMVERTICES];
    4777         double vz[NUMVERTICES];
    4778         double vel[NUMVERTICES];
    4779         double pressure[NUMVERTICES];
    4780         double surface[NUMVERTICES];
    4781         double xyz_list[NUMVERTICES][3];
    4782         int*   doflist = NULL;
    4783         double *vz_ptr = NULL;
    4784 
    4785         /*Get dof list: */
    4786         GetDofList(&doflist,PattynApproximationEnum,GsetEnum);
    4787 
    4788         /*Get node data: */
    4789         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4790 
    4791         /*Use the dof list to index into the solution vector: */
    4792         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4793 
    4794         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4795         for(i=0;i<NUMVERTICES;i++){
    4796                 vx[i]=values[i*NDOF2+0];
    4797                 vy[i]=values[i*NDOF2+1];
    4798         }
    4799 
    4800         /*Get Vz*/
    4801         Input* vz_input=inputs->GetInput(VzEnum);
    4802         if (vz_input){
    4803                 if (vz_input->Enum()!=PentaVertexInputEnum){
    4804                         ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
    4805                 }
    4806                 vz_input->GetValuesPtr(&vz_ptr,&dummy);
    4807                 for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
    4808         }
    4809         else{
    4810                 for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
    4811         }
    4812 
    4813         /*Now Compute vel*/
    4814         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4815 
    4816         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
    4817          *so the pressure is just the pressure at the z elevation: */
    4818         rho_ice=matpar->GetRhoIce();
    4819         g=matpar->GetG();
    4820         GetParameterListOnVertices(&surface[0],SurfaceEnum);
    4821         for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
    4822 
    4823         /*Now, we have to move the previous Vx and Vy inputs  to old
    4824          * status, otherwise, we'll wipe them off: */
    4825         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4826         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4827         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4828 
    4829         /*Add vx and vy as inputs to the tria element: */
    4830         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4831         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4832         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    4833         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4834 
    4835         /*Free ressources:*/
    4836         xfree((void**)&doflist);
    4837 }
    4838 /*}}}*/
    4839 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattynStokes {{{1*/
    4840 void  Penta::InputUpdateFromSolutionDiagnosticPattynStokes(double* solution){
    4841 
    4842         const int    numdofp=NDOF2*NUMVERTICES;
    4843         const int    numdofs=NDOF4*NUMVERTICES;
    4844 
    4845         int    i,dummy;
    4846         double pattyn_values[numdofp];
    4847         double stokes_values[numdofs];
    4848         double vx[NUMVERTICES];
    4849         double vy[NUMVERTICES];
    4850         double vz[NUMVERTICES];
    4851         double vzpattyn[NUMVERTICES];
    4852         double vzstokes[NUMVERTICES];
    4853         double vel[NUMVERTICES];
    4854         double pressure[NUMVERTICES];
    4855         double xyz_list[NUMVERTICES][3];
    4856         double stokesreconditioning;
    4857         int*   doflistp      = NULL;
    4858         int*   doflists      = NULL;
    4859         double *vzpattyn_ptr = NULL;
    4860         Penta  *penta        = NULL;
    4861 
    4862         /*OK, we have to add results of this element for pattyn
    4863          * and results from the penta at base for macayeal. Now recover results*/
    4864         penta=GetBasalElement();
    4865 
    4866         /*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
    4867         GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
    4868         GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
    4869         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    4870 
    4871         /*Get node data: */
    4872         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4873 
    4874         /*Use the dof list to index into the solution vector: */
    4875         for(i=0;i<numdofp;i++) pattyn_values[i]=solution[doflistp[i]];
    4876         for(i=0;i<numdofs;i++) stokes_values[i]=solution[doflists[i]];
    4877 
    4878         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4879         for(i=0;i<NUMVERTICES;i++){
    4880                 vx[i]=stokes_values[i*NDOF4+0]+pattyn_values[i*NDOF2+0];
    4881                 vy[i]=stokes_values[i*NDOF4+1]+pattyn_values[i*NDOF2+1];
    4882                 vzstokes[i]=stokes_values[i*NDOF4+2];
    4883                 pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
    4884         }
    4885 
    4886         /*Get Vz*/
    4887         Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
    4888         if (vzpattyn_input){
    4889                 if (vzpattyn_input->Enum()!=PentaVertexInputEnum){
    4890                         ISSMERROR("Cannot compute Vel as VzPattyn is of type %s",EnumToString(vzpattyn_input->Enum()));
    4891                 }
    4892                 vzpattyn_input->GetValuesPtr(&vzpattyn_ptr,&dummy);
    4893                 for(i=0;i<NUMVERTICES;i++) vzpattyn[i]=vzpattyn_ptr[i];
    4894         }
    4895         else{
    4896                 ISSMERROR("Cannot update solution as VzPattyn is not present");
    4897         }
    4898 
    4899         /*Now Compute vel*/
    4900         for(i=0;i<NUMVERTICES;i++) {
    4901                 vz[i]=vzpattyn[i]+vzstokes[i];
    4902                 vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4903         }
    4904 
    4905         /*Now, we have to move the previous Vx and Vy inputs  to old
    4906          * status, otherwise, we'll wipe them off: */
    4907         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4908         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4909         this->inputs->ChangeEnum(VzEnum,VzOldEnum);
    4910         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4911 
    4912         /*Add vx and vy as inputs to the tria element: */
    4913         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4914         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4915         this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
    4916         this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
    4917         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    4918         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4919 
    4920         /*Free ressources:*/
    4921         xfree((void**)&doflistp);
    4922         xfree((void**)&doflists);
    4923 }
    4924 /*}}}*/
    4925 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHutter {{{1*/
    4926 void  Penta::InputUpdateFromSolutionDiagnosticHutter(double* solution){
    4927        
    4928         const int    numdof=NDOF2*NUMVERTICES;
    4929 
    4930         int     i,dummy;
    4931         double  rho_ice,g;
    4932         double  values[numdof];
    4933         double  vx[NUMVERTICES];
    4934         double  vy[NUMVERTICES];
    4935         double  vz[NUMVERTICES];
    4936         double  vel[NUMVERTICES];
    4937         double  pressure[NUMVERTICES];
    4938         double  surface[NUMVERTICES];
    4939         double  xyz_list[NUMVERTICES][3];
    4940         int*    doflist = NULL;
    4941         double* vz_ptr  = NULL;
    4942 
    4943         /*Get dof list: */
    4944         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4945 
    4946         /*Get node data: */
    4947         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4948 
    4949         /*Use the dof list to index into the solution vector: */
    4950         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4951 
    4952         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4953         for(i=0;i<NUMVERTICES;i++){
    4954                 vx[i]=values[i*NDOF2+0];
    4955                 vy[i]=values[i*NDOF2+1];
    4956         }
    4957 
    4958         /*Get Vz*/
    4959         Input* vz_input=inputs->GetInput(VzEnum);
    4960         if (vz_input){
    4961                 if (vz_input->Enum()!=PentaVertexInputEnum){
    4962                         ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
    4963                 }
    4964                 vz_input->GetValuesPtr(&vz_ptr,&dummy);
    4965                 for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
    4966         }
    4967         else{
    4968                 for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
    4969         }
    4970 
    4971         /*Now Compute vel*/
    4972         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4973 
    4974         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
    4975          *so the pressure is just the pressure at the z elevation: */
    4976         rho_ice=matpar->GetRhoIce();
    4977         g=matpar->GetG();
    4978         GetParameterListOnVertices(&surface[0],SurfaceEnum);
    4979         for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
    4980 
    4981         /*Now, we have to move the previous Vx and Vy inputs  to old
    4982          * status, otherwise, we'll wipe them off: */
    4983         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4984         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4985         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4986 
    4987         /*Add vx and vy as inputs to the tria element: */
    4988         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    4989         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    4990         this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
    4991         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    4992 
    4993         /*Free ressources:*/
    4994         xfree((void**)&doflist);
    4995 }
    4996 /*}}}*/
    4997 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticVert {{{1*/
    4998 void  Penta::InputUpdateFromSolutionDiagnosticVert(double* solution){
    4999 
    5000         const int numdof=NDOF1*NUMVERTICES;
    5001        
    5002         int      i,dummy;
    5003         int      approximation;
    5004         double   rho_ice,g;
    5005         double   values[numdof];
    5006         double   vx[NUMVERTICES];
    5007         double   vy[NUMVERTICES];
    5008         double   vz[NUMVERTICES];
    5009         double   vzmacayeal[NUMVERTICES];
    5010         double   vzpattyn[NUMVERTICES];
    5011         double   vzstokes[NUMVERTICES];
    5012         double   vel[NUMVERTICES];
    5013         double   pressure[NUMVERTICES];
    5014         double   surface[NUMVERTICES];
    5015         double   xyz_list[NUMVERTICES][3];
    5016         int*     doflist      = NULL;
    5017         double*  vx_ptr       = NULL;
    5018         double*  vy_ptr       = NULL;
    5019         double*  vzstokes_ptr = NULL;
    5020 
    5021 
    5022         /*Get the approximation and do nothing if the element in Stokes or None*/
    5023         inputs->GetParameterValue(&approximation,ApproximationEnum);
    5024         if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
    5025                 return;
    5026         }
    5027 
    5028         /*Get dof list and vertices coordinates: */
    5029         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5030         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    5031 
    5032         /*Use the dof list to index into the solution vector vz: */
    5033         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5034         for(i=0;i<NUMVERTICES;i++) vz[i]=values[i*NDOF1+0];
    5035 
    5036         /*Get Vx and Vy*/
    5037         Input* vx_input=inputs->GetInput(VxEnum);
    5038         if (vx_input){
    5039                 if (vx_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vx is of type %s",EnumToString(vx_input->Enum()));
    5040                 vx_input->GetValuesPtr(&vx_ptr,&dummy);
    5041                 for(i=0;i<NUMVERTICES;i++) vx[i]=vx_ptr[i];
    5042         }
    5043         else for(i=0;i<NUMVERTICES;i++) vx[i]=0.0;
    5044 
    5045         Input* vy_input=inputs->GetInput(VyEnum);
    5046         if (vy_input){
    5047                 if (vy_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vy is of type %s",EnumToString(vy_input->Enum()));
    5048                 vy_input->GetValuesPtr(&vy_ptr,&dummy);
    5049                 for(i=0;i<NUMVERTICES;i++) vy[i]=vy_ptr[i];
    5050         }
    5051         else for(i=0;i<NUMVERTICES;i++) vy[i]=0.0;
    5052 
    5053         /*Do some modifications if we actually have a PattynStokes or MacAyealStokes element*/
    5054         if(approximation==PattynStokesApproximationEnum){
    5055                 Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
    5056                 if (vzstokes_input){
    5057                         if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
    5058                         vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
    5059                         for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
    5060                 }
    5061                 else ISSMERROR("Cannot compute Vz as VzStokes in not present in PattynStokes element");
    5062                 for(i=0;i<NUMVERTICES;i++){
    5063                         vzpattyn[i]=vz[i];
    5064                         vz[i]=vzpattyn[i]+vzstokes[i];
    5065                 }
    5066         }
    5067         else if(approximation==MacAyealStokesApproximationEnum){
    5068                 Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
    5069                 if (vzstokes_input){
    5070                         if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
    5071                         vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
    5072                         for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
    5073                 }
    5074                 else ISSMERROR("Cannot compute Vz as VzStokes in not present in MacAyealStokes element");
    5075                 for(i=0;i<NUMVERTICES;i++){
    5076                         vzmacayeal[i]=vz[i];
    5077                         vz[i]=vzmacayeal[i]+vzstokes[i];
    5078                 }
    5079         }
    5080 
    5081         /*Now Compute vel*/
    5082         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    5083 
    5084         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D,
    5085          *so the pressure is just the pressure at the z elevation: except it this is a PattynStokes element */
    5086         if(approximation!=PattynStokesApproximationEnum &&  approximation!=MacAyealStokesApproximationEnum){
    5087                 rho_ice=matpar->GetRhoIce();
    5088                 g=matpar->GetG();
    5089                 GetParameterListOnVertices(&surface[0],SurfaceEnum);
    5090                 for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
    5091         }
    5092 
    5093         /*Now, we have to move the previous Vz inputs to old
    5094          * status, otherwise, we'll wipe them off and add the new inputs: */
    5095         this->inputs->ChangeEnum(VzEnum,VzOldEnum);
    5096 
    5097         if(approximation!=PattynStokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum){
    5098                 this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    5099                 this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    5100         }
    5101         else if(approximation==PattynStokesApproximationEnum){
    5102                 this->inputs->AddInput(new PentaVertexInput(VzPattynEnum,vzpattyn));
    5103         }
    5104         else if(approximation==MacAyealStokesApproximationEnum){
    5105                 this->inputs->AddInput(new PentaVertexInput(VzMacAyealEnum,vzpattyn));
    5106         }
    5107 
    5108         this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
    5109         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    5110 
    5111         /*Free ressources:*/
    5112         xfree((void**)&doflist);
    5113 }
    5114 /*}}}*/
    5115 /*FUNCTION Penta::InputUpdateFromSolutionDiagnosticStokes {{{1*/
    5116 void  Penta::InputUpdateFromSolutionDiagnosticStokes(double* solution){
    5117        
    5118         const int numdof=NDOF4*NUMVERTICES;
    5119 
    5120         int     i;
    5121         double  values[numdof];
    5122         double  vx[NUMVERTICES];
    5123         double  vy[NUMVERTICES];
    5124         double  vz[NUMVERTICES];
    5125         double  vel[NUMVERTICES];
    5126         double  pressure[NUMVERTICES];
    5127         double  stokesreconditioning;
    5128         int*    doflist=NULL;
    5129 
    5130         /*Get dof list: */
    5131         GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
    5132 
    5133         /*Use the dof list to index into the solution vector: */
    5134         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5135 
    5136         /*Ok, we have vx and vy in values, fill in all arrays: */
    5137         for(i=0;i<NUMVERTICES;i++){
    5138                 vx[i]=values[i*NDOF4+0];
    5139                 vy[i]=values[i*NDOF4+1];
    5140                 vz[i]=values[i*NDOF4+2];
    5141                 pressure[i]=values[i*NDOF4+3];
    5142         }
    5143 
    5144         /*Recondition pressure and compute vel: */
    5145         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    5146         for(i=0;i<NUMVERTICES;i++) pressure[i]=pressure[i]*stokesreconditioning;
    5147         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    5148        
    5149         /*Now, we have to move the previous inputs  to old
    5150          * status, otherwise, we'll wipe them off: */
    5151         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    5152         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    5153         this->inputs->ChangeEnum(VzEnum,VzOldEnum);
    5154         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    5155 
    5156         /*Add vx and vy as inputs to the tria element: */
    5157         this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
    5158         this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
    5159         this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
    5160         this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
    5161         this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
    5162 
    5163         /*Free ressources:*/
    5164         xfree((void**)&doflist);
    5165 }
    5166 /*}}}*/
    5167 /*FUNCTION Penta::InputUpdateFromSolutionAdjointStokes {{{1*/
    5168 void  Penta::InputUpdateFromSolutionAdjointStokes(double* solution){
    5169 
    5170         const int    numdof=NDOF4*NUMVERTICES;
    5171 
    5172         int    i;
    5173         double values[numdof];
    5174         double lambdax[NUMVERTICES];
    5175         double lambday[NUMVERTICES];
    5176         double lambdaz[NUMVERTICES];
    5177         double lambdap[NUMVERTICES];
    5178         int*   doflist=NULL;
    5179 
    5180         /*Get dof list: */
    5181         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5182 
    5183         /*Use the dof list to index into the solution vector: */
    5184         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5185 
    5186         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    5187         for(i=0;i<NUMVERTICES;i++){
    5188                 lambdax[i]=values[i*NDOF4+0];
    5189                 lambday[i]=values[i*NDOF4+1];
    5190                 lambdaz[i]=values[i*NDOF4+2];
    5191                 lambdap[i]=values[i*NDOF4+3];
    5192         }
    5193 
    5194         /*Add vx and vy as inputs to the tria element: */
    5195         this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
    5196         this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
    5197         this->inputs->AddInput(new PentaVertexInput(AdjointzEnum,lambdaz));
    5198         this->inputs->AddInput(new PentaVertexInput(AdjointpEnum,lambdap));
    5199 
    5200         /*Free ressources:*/
    5201         xfree((void**)&doflist);
    5202 }
    5203 /*}}}*/
    5204 /*FUNCTION Penta::InputUpdateFromSolutionAdjointHoriz {{{1*/
    5205 void  Penta::InputUpdateFromSolutionAdjointHoriz(double* solution){
    5206 
    5207         const int numdof=NDOF2*NUMVERTICES;
    5208 
    5209         int    i;
    5210         double values[numdof];
    5211         double lambdax[NUMVERTICES];
    5212         double lambday[NUMVERTICES];
    5213         int*   doflist=NULL;
    5214 
    5215         /*Get dof list: */
    5216         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5217 
    5218         /*Use the dof list to index into the solution vector: */
    5219         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5220 
    5221         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    5222         for(i=0;i<NUMVERTICES;i++){
    5223                 lambdax[i]=values[i*NDOF2+0];
    5224                 lambday[i]=values[i*NDOF2+1];
    5225         }
    5226 
    5227         /*Add vx and vy as inputs to the tria element: */
    5228         this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
    5229         this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
    5230 
    5231         /*Free ressources:*/
    5232         xfree((void**)&doflist);
    5233 }
    5234 /*}}}*/
    5235 /*FUNCTION Penta::InputUpdateFromSolutionThermal {{{1*/
    5236 void  Penta::InputUpdateFromSolutionThermal(double* solution){
    5237 
    5238         const int    numdof=NDOF1*NUMVERTICES;
    5239 
    5240         bool   converged;
    5241         int    i;
    5242         double values[numdof];
    5243         double B[numdof];
    5244         double B_average;
    5245         int*   doflist=NULL;
    5246 
    5247         /*Get dof list: */
    5248         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5249 
    5250         /*Use the dof list to index into the solution vector: */
    5251         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5252 
    5253         this->inputs->GetParameterValue(&converged,ConvergedEnum);
    5254         if(converged){
    5255                 this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,values));
    5256 
    5257                 /*Update Rheology only if convreged (we must make sure that the temperature is below melting point
    5258                  * otherwise the rheology could be negative*/
    5259                 B_average=Paterson((values[0]+values[1]+values[2]+values[3]+values[4]+values[5])/6.0);
    5260                 for(i=0;i<numdof;i++) B[i]=B_average;
    5261                 this->matice->inputs->AddInput(new PentaVertexInput(RheologyBEnum,B));
    5262         }
    5263         else{
    5264                 this->inputs->AddInput(new PentaVertexInput(TemporaryTemperatureEnum,values));
    5265         }
    5266 
    5267         /*Free ressources:*/
    5268         xfree((void**)&doflist);
    5269 }
    5270 /*}}}*/
    5271 /*FUNCTION Penta::InputUpdateFromSolutionOneDof{{{1*/
    5272 void  Penta::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
    5273 
    5274         const int numdof = NDOF1*NUMVERTICES;
    5275 
    5276         double values[numdof];
    5277         int*   doflist=NULL;
    5278 
    5279         /*Get dof list: */
    5280         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5281 
    5282         /*Use the dof list to index into the solution vector: */
    5283         for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5284 
    5285         /*Add input to the element: */
    5286         this->inputs->AddInput(new PentaVertexInput(enum_type,values));
    5287        
    5288         /*Free ressources:*/
    5289         xfree((void**)&doflist);
    5290 }
    5291 /*}}}*/
    5292 /*FUNCTION Penta::InputUpdateFromSolutionOneDofCollpased{{{1*/
    5293 void  Penta::InputUpdateFromSolutionOneDofCollapsed(double* solution,int enum_type){
    5294 
    5295         const int  numdof   = NDOF1*NUMVERTICES;
    5296         const int  numdof2d = NDOF1*NUMVERTICES2D;
    5297 
    5298         double  values[numdof];
    5299         int*    doflist = NULL;
    5300         Penta  *penta   = NULL;
    5301 
    5302         /*If not on bed, return*/
    5303         if (!IsOnBed()) return;
    5304 
    5305         /*Get dof list: */
    5306         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5307 
    5308         /*Use the dof list to index into the solution vector and extrude it */
    5309         for(int i=0;i<numdof2d;i++){
    5310                 values[i]         =solution[doflist[i]];
    5311                 values[i+numdof2d]=values[i];
    5312         }
    5313 
    5314         /*Start looping over all elements above current element and update all inputs*/
    5315         penta=this;
    5316         for(;;){
    5317                 /*Add input to the element: */
    5318                 penta->inputs->AddInput(new PentaVertexInput(enum_type,values));
    5319 
    5320                 /*Stop if we have reached the surface*/
    5321                 if (penta->IsOnSurface()) break;
    5322 
    5323                 /* get upper Penta*/
    5324                 penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
    5325         }
    5326        
    5327         /*Free ressources:*/
    5328         xfree((void**)&doflist);
    5329 }
    5330 /*}}}*/
    5331 /*FUNCTION Penta::IsInput{{{1*/
    5332 bool Penta::IsInput(int name){
    5333         if (
    5334                                 name==ThicknessEnum ||
    5335                                 name==SurfaceEnum ||
    5336                                 name==BedEnum ||
    5337                                 name==DtEnum ||
    5338                                 name==SurfaceSlopeXEnum ||
    5339                                 name==SurfaceSlopeYEnum ||
    5340                                 name==MeltingRateEnum ||
    5341                                 name==AccumulationRateEnum ||
    5342                                 name==GeothermalFluxEnum ||
    5343                                 name==SurfaceAreaEnum||
    5344                                 name==PressureEnum ||
    5345                                 name==VxEnum ||
    5346                                 name==VyEnum ||
    5347                                 name==VzEnum ||
    5348                                 name==VxObsEnum ||
    5349                                 name==VyObsEnum ||
    5350                                 name==VzObsEnum ||
    5351                                 name==TemperatureEnum ||
    5352                                 name==CmResponseEnum ||
    5353                                 name==DragCoefficientEnum ||
    5354                                 name==GradientEnum ||
    5355                                 name==OldGradientEnum  ||
    5356                                 name==ConvergedEnum
    5357                                 ) {
    5358                 return true;
    5359         }
    5360         else return false;
    5361 }
    5362 /*}}}*/
    5363 /*FUNCTION Penta::IsOnShelf {{{1*/
    5364 bool   Penta::IsOnShelf(){
    5365 
    5366         bool onshelf;
    5367         inputs->GetParameterValue(&onshelf,ElementOnIceShelfEnum);
    5368         return onshelf;
    5369 }
    5370 /*}}}*/
    5371 /*FUNCTION Penta::IsOnWater {{{1*/
    5372 bool   Penta::IsOnWater(){
    5373 
    5374         bool onwater;
    5375         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    5376         return onwater;
    5377 }
    5378 /*}}}*/
    5379 /*FUNCTION Penta::IsOnSurface{{{1*/
    5380 bool Penta::IsOnSurface(void){
    5381 
    5382         bool onsurface;
    5383         inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
    5384         return onsurface;
    5385 }
    5386 /*}}}*/
    5387 /*FUNCTION Penta::IsOnBed{{{1*/
    5388 bool Penta::IsOnBed(void){
    5389 
    5390         bool onbed;
    5391         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    5392         return onbed;
    5393 }
    5394 /*}}}*/
    5395 /*FUNCTION Penta::MinEdgeLength{{{1*/
    5396 double Penta::MinEdgeLength(double xyz_list[6][3]){
    5397         /*Return the minimum lenght of the nine egdes of the penta*/
    5398 
    5399         int    i,node0,node1;
    5400         int    edges[9][2]={{0,1},{0,2},{1,2},{3,4},{3,5},{4,5},{0,3},{1,4},{2,5}}; //list of the nine edges
    5401         double length;
    5402         double minlength=-1;
    5403        
    5404         for(i=0;i<9;i++){
    5405                 /*Find the two nodes for this edge*/
    5406                 node0=edges[i][0];
    5407                 node1=edges[i][1];
    5408 
    5409                 /*Compute the length of this edge and compare it to the minimal length*/
    5410                 length=pow(pow(xyz_list[node0][0]-xyz_list[node1][0],2.0)+pow(xyz_list[node0][1]-xyz_list[node1][1],2.0)+pow(xyz_list[node0][2]-xyz_list[node1][2],2.0),0.5);
    5411                 if(length<minlength || minlength<0) minlength=length;
    5412         }
    5413 
    5414         return minlength;
    5415 }
    5416 /*}}}*/
    5417 /*FUNCTION Penta::ReduceMatrixStokes {{{1*/
    5418 void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
    5419 
    5420         int    i,j;
    5421         double Kii[24][24];
    5422         double Kib[24][3];
    5423         double Kbb[3][3];
    5424         double Kbi[3][24];
    5425         double Kbbinv[3][3];
    5426         double Kright[24][24];
    5427 
    5428         /*Create the four matrices used for reduction */
    5429         for(i=0;i<24;i++){
    5430                 for(j=0;j<24;j++){
    5431                         Kii[i][j]=*(Ke_temp+27*i+j);
    5432                 }
    5433                 for(j=0;j<3;j++){
    5434                         Kib[i][j]=*(Ke_temp+27*i+j+24);
    5435                 }
    5436         }
    5437         for(i=0;i<3;i++){
    5438                 for(j=0;j<24;j++){
    5439                         Kbi[i][j]=*(Ke_temp+27*(i+24)+j);
    5440                 }
    5441                 for(j=0;j<3;j++){
    5442                         Kbb[i][j]=*(Ke_temp+27*(i+24)+j+24);
    5443                 }
    5444         }
    5445 
    5446         /*Inverse the matrix corresponding to bubble part Kbb */
    5447         Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
    5448 
    5449         /*Multiply matrices to create the reduce matrix Ke_reduced */
    5450         TripleMultiply(&Kib[0][0],24,3,0,
    5451                                 &Kbbinv[0][0],3,3,0,
    5452                                 &Kbi[0][0],3,24,0,
    5453                                 &Kright[0][0],0);
    5454 
    5455         /*Affect value to the reduced matrix */
    5456         for(i=0;i<24;i++) for(j=0;j<24;j++) *(Ke_reduced+24*i+j)=Kii[i][j]-Kright[i][j];
    5457 }
    5458 /*}}}*/
    5459 /*FUNCTION Penta::ReduceVectorStokes {{{1*/
    5460 void Penta::ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp){
    5461 
    5462         int    i,j;
    5463         double Pi[24];
    5464         double Pb[3];
    5465         double Kbb[3][3];
    5466         double Kib[24][3];
    5467         double Kbbinv[3][3];
    5468         double Pright[24];
    5469 
    5470         /*Create the four matrices used for reduction */
    5471         for(i=0;i<24;i++) Pi[i]=*(Pe_temp+i);
    5472         for(i=0;i<3;i++) Pb[i]=*(Pe_temp+i+24);
    5473         for(j=0;j<3;j++){
    5474                 for(i=0;i<24;i++){
    5475                         Kib[i][j]=*(Ke_temp+3*i+j);
    5476                 }
    5477                 for(i=0;i<3;i++){
    5478                         Kbb[i][j]=*(Ke_temp+3*(i+24)+j);
    5479                 }
    5480         }
    5481 
    5482         /*Inverse the matrix corresponding to bubble part Kbb */
    5483         Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
    5484 
    5485         /*Multiply matrices to create the reduce matrix Ke_reduced */
    5486         TripleMultiply(&Kib[0][0],24,3,0,
    5487                                 &Kbbinv[0][0],3,3,0,
    5488                                 &Pb[0],3,1,0,&Pright[0],0);
    5489 
    5490         /*Affect value to the reduced matrix */
    5491         for(i=0;i<24;i++) *(Pe_reduced+i)=Pi[i]-Pright[i];
    5492 }
    5493 /*}}}*/
    5494 /*FUNCTION Penta::SetClone {{{1*/
    5495 void  Penta::SetClone(int* minranks){
    5496 
    5497         ISSMERROR("not implemented yet");
    5498 }
    5499 /*}}}1*/
    5500 /*FUNCTION Penta::SpawnTria {{{1*/
    5501 Tria*  Penta::SpawnTria(int g0, int g1, int g2){
    5502 
    5503         int   i,analysis_counter;
    5504         int   indices[3];
    5505         int   zero=0;
    5506         Tria*       tria            = NULL;
    5507         Inputs*     tria_inputs     = NULL;
    5508         Results*    tria_results    = NULL;
    5509         Parameters* tria_parameters = NULL;
    5510        
    5511         /*go into parameters and get the analysis_counter: */
    5512         this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
    5513 
    5514         indices[0]=g0;
    5515         indices[1]=g1;
    5516         indices[2]=g2;
    5517 
    5518         tria_parameters=this->parameters;
    5519         tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
    5520         tria_results=(Results*)this->results->SpawnTriaResults(indices);
    5521        
    5522         tria=new Tria();
    5523         tria->id=this->id;
    5524         tria->inputs=tria_inputs;
    5525         tria->results=tria_results;
    5526         tria->parameters=tria_parameters;
    5527         tria->element_type=P1Enum; //Only P1 CG for now (TO BE CHANGED)
    5528         this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
    5529 
    5530         /*Spawn matice*/
    5531         tria->matice=NULL;
    5532         tria->matice=(Matice*)this->matice->copy();
    5533         delete tria->matice->inputs;
    5534         tria->matice->inputs=(Inputs*)this->matice->inputs->SpawnTriaInputs(indices);
    5535 
    5536         /*recover nodes, matice and matpar: */
    5537         tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
    5538         tria->matpar=(Matpar*)tria->hmatpar->delivers();
    5539        
    5540         return tria;
    5541 }
    5542 /*}}}*/
    5543 /*FUNCTION Penta::SurfaceNormal {{{1*/
    5544 void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
    5545 
    5546         int    i;
    5547         double v13[3],v23[3];
    5548         double normal[3];
    5549         double normal_norm;
    5550 
    5551         for (i=0;i<3;i++){
    5552                 v13[i]=xyz_list[0][i]-xyz_list[2][i];
    5553                 v23[i]=xyz_list[1][i]-xyz_list[2][i];
    5554         }
    5555 
    5556         normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
    5557         normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
    5558         normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
    5559 
    5560         normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
    5561 
    5562         *(surface_normal)=normal[0]/normal_norm;
    5563         *(surface_normal+1)=normal[1]/normal_norm;
    5564         *(surface_normal+2)=normal[2]/normal_norm;
    5565 }
    5566 /*}}}*/
  • issm/trunk/src/c/objects/Elements/Tria.cpp

    r6397 r6410  
    2626#define NDOF4 4
    2727
    28 /*Tria constructors and destructor*/
     28/*Constructors/destructor/copy*/
    2929/*FUNCTION Tria::Tria(){{{1*/
    3030Tria::Tria(){
     
    6767}
    6868/*}}}*/
    69 
    70 /*Object virtual functions definitions:*/
    7169/*FUNCTION Tria::copy {{{1*/
    7270Object* Tria::copy() {
     
    104102        /*point parameters: */
    105103        tria->parameters=this->parameters;
    106        
     104
    107105        /*recover objects: */
    108106        tria->nodes=(Node**)xmalloc(3*sizeof(Node*)); //we cannot rely on an analysis_counter to tell us which analysis_type we are running, so we just copy the nodes.
     
    114112}
    115113/*}}}*/
    116 /*FUNCTION Tria::DeepEcho{{{1*/
    117 void Tria::DeepEcho(void){
    118 
    119         printf("Tria:\n");
    120         printf("   id: %i\n",id);
    121         if(nodes){
    122                 nodes[0]->DeepEcho();
    123                 nodes[1]->DeepEcho();
    124                 nodes[2]->DeepEcho();
    125         }
    126         else printf("nodes = NULL\n");
    127 
    128         if (matice) matice->DeepEcho();
    129         else printf("matice = NULL\n");
    130 
    131         if (matpar) matpar->DeepEcho();
    132         else printf("matpar = NULL\n");
    133 
    134         printf("   parameters\n");
    135         if (parameters) parameters->DeepEcho();
    136         else printf("parameters = NULL\n");
    137 
    138         printf("   inputs\n");
    139         if (inputs) inputs->DeepEcho();
    140         else printf("inputs=NULL\n");
    141 
    142         if (results) results->DeepEcho();
    143         else printf("results=NULL\n");
    144        
    145         return;
    146 }
    147 /*}}}*/
    148 /*FUNCTION Tria::Demarshall {{{1*/
    149 void  Tria::Demarshall(char** pmarshalled_dataset){
    150 
    151         char* marshalled_dataset=NULL;
    152         int i;
    153         int flaghook;
    154 
    155         /*recover marshalled_dataset: */
    156         marshalled_dataset=*pmarshalled_dataset;
    157 
    158         /*this time, no need to get enum type, the pointer directly points to the beginning of the
    159          *object data (thanks to DataSet::Demarshall):*/
    160         memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
    161         memcpy(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
    162 
    163         /*demarshall Ref: */
    164         this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
    165         for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
    166 
    167         /*allocate dynamic memory: */
    168         this->hnodes=new Hook*[this->numanalyses];
    169         /*demarshall hooks: */
    170         for(i=0;i<numanalyses;i++){
    171                 memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
    172                 if(flaghook){ // there is a hook so demarshall it
    173                         hnodes[i]=new Hook();
    174                         hnodes[i]->Demarshall(&marshalled_dataset);
    175                 }
    176                 else hnodes[i]=NULL; //There is no hook so it is NULL
    177         }
    178         hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
    179         hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
    180 
    181         /*pointers are garbabe, until configuration is carried out: */
    182         nodes=NULL;
    183         matice=NULL;
    184         matpar=NULL;
    185        
    186         /*demarshall inputs: */
    187         inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset);
    188         results=(Results*)DataSetDemarshallRaw(&marshalled_dataset);
    189 
    190         /*parameters: may not exist even yet, so let Configure handle it: */
    191         this->parameters=NULL;
    192 
    193         /*return: */
    194         *pmarshalled_dataset=marshalled_dataset;
    195         return;
    196 }
    197 /*}}}*/
    198 /*FUNCTION Tria::Echo{{{1*/
    199 void Tria::Echo(void){
    200         printf("Tria:\n");
    201         printf("   id: %i\n",id);
    202         if(nodes){
    203                 nodes[0]->Echo();
    204                 nodes[1]->Echo();
    205                 nodes[2]->Echo();
    206         }
    207         else printf("nodes = NULL\n");
    208 
    209         if (matice) matice->Echo();
    210         else printf("matice = NULL\n");
    211 
    212         if (matpar) matpar->Echo();
    213         else printf("matpar = NULL\n");
    214 
    215         printf("   parameters\n");
    216         if (parameters) parameters->Echo();
    217         else printf("parameters = NULL\n");
    218 
    219         printf("   inputs\n");
    220         if (inputs) inputs->Echo();
    221         else printf("inputs=NULL\n");
    222 
    223         if (results) results->Echo();
    224         else printf("results=NULL\n");
    225 }
    226 /*}}}*/
    227 /*FUNCTION Tria::Enum {{{1*/
    228 int Tria::Enum(void){
    229 
    230         return TriaEnum;
    231 
    232 }
    233 /*}}}*/
    234 /*FUNCTION Tria::Id {{{1*/
    235 int    Tria::Id(){
    236        
    237         return id;
    238 
    239 }
    240 /*}}}*/
     114
     115/*Marshall*/
    241116/*FUNCTION Tria::Marshall {{{1*/
    242117void  Tria::Marshall(char** pmarshalled_dataset){
     
    269144        }
    270145
    271  /*Marshall hooks: */
     146        /*Marshall hooks: */
    272147        for(i=0;i<numanalyses;i++){
    273148                if(hnodes[i]){
     
    319194
    320195        return sizeof(id)
    321                 +hnodes_size
    322                 +sizeof(numanalyses)
    323                 +numanalyses*sizeof(int) //element_type_lists
    324                 +hmatice->MarshallSize()
    325                 +hmatpar->MarshallSize()
    326                 +inputs->MarshallSize()
    327                 +results->MarshallSize()
    328                 +sizeof(int); //sizeof(int) for enum type
    329 }
    330 /*}}}*/
    331 /*FUNCTION Tria::MyRank {{{1*/
    332 int    Tria::MyRank(void){
    333         extern int my_rank;
    334         return my_rank;
    335 }
    336 /*}}}*/
    337 
    338 /*Update virtual functions definitions: */
     196          +hnodes_size
     197          +sizeof(numanalyses)
     198          +numanalyses*sizeof(int) //element_type_lists
     199          +hmatice->MarshallSize()
     200          +hmatpar->MarshallSize()
     201          +inputs->MarshallSize()
     202          +results->MarshallSize()
     203          +sizeof(int); //sizeof(int) for enum type
     204}
     205/*}}}*/
     206/*FUNCTION Tria::Demarshall {{{1*/
     207void  Tria::Demarshall(char** pmarshalled_dataset){
     208
     209        char* marshalled_dataset=NULL;
     210        int i;
     211        int flaghook;
     212
     213        /*recover marshalled_dataset: */
     214        marshalled_dataset=*pmarshalled_dataset;
     215
     216        /*this time, no need to get enum type, the pointer directly points to the beginning of the
     217         *object data (thanks to DataSet::Demarshall):*/
     218        memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
     219        memcpy(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
     220
     221        /*demarshall Ref: */
     222        this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
     223        for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
     224
     225        /*allocate dynamic memory: */
     226        this->hnodes=new Hook*[this->numanalyses];
     227        /*demarshall hooks: */
     228        for(i=0;i<numanalyses;i++){
     229                memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
     230                if(flaghook){ // there is a hook so demarshall it
     231                        hnodes[i]=new Hook();
     232                        hnodes[i]->Demarshall(&marshalled_dataset);
     233                }
     234                else hnodes[i]=NULL; //There is no hook so it is NULL
     235        }
     236        hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
     237        hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
     238
     239        /*pointers are garbabe, until configuration is carried out: */
     240        nodes=NULL;
     241        matice=NULL;
     242        matpar=NULL;
     243       
     244        /*demarshall inputs: */
     245        inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset);
     246        results=(Results*)DataSetDemarshallRaw(&marshalled_dataset);
     247
     248        /*parameters: may not exist even yet, so let Configure handle it: */
     249        this->parameters=NULL;
     250
     251        /*return: */
     252        *pmarshalled_dataset=marshalled_dataset;
     253        return;
     254}
     255/*}}}*/
     256
     257/*Other*/
     258/*FUNCTION Tria::AverageOntoPartition {{{1*/
     259void  Tria::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
     260
     261        bool      already=false;
     262        int       i,j;
     263        int       partition[NUMVERTICES];
     264        int       offsetsid[NUMVERTICES];
     265        int       offsetdof[NUMVERTICES];
     266        double    area;
     267        double    mean;
     268        double    values[3];
     269
     270        /*First, get the area: */
     271        area=this->GetArea();
     272
     273        /*Figure out the average for this element: */
     274        this->GetSidList(&offsetsid[0]);
     275        this->GetDofList1(&offsetdof[0]);
     276        mean=0;
     277        for(i=0;i<NUMVERTICES;i++){
     278                partition[i]=(int)qmu_part[offsetsid[i]];
     279                mean=mean+1.0/NUMVERTICES*vertex_response[offsetdof[i]];
     280        }
     281
     282        /*Add contribution: */
     283        for(i=0;i<NUMVERTICES;i++){
     284                already=false;
     285                for(j=0;j<i;j++){
     286                        if (partition[i]==partition[j]){
     287                                already=true;
     288                                break;
     289                        }
     290                }
     291                if(!already){
     292                        VecSetValue(partition_contributions,partition[i],mean*area,ADD_VALUES);
     293                        VecSetValue(partition_areas,partition[i],area,ADD_VALUES);
     294                };
     295        }
     296}
     297/*}}}*/
     298/*FUNCTION Tria::CreateKMatrix {{{1*/
     299void  Tria::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
     300
     301        /*retreive parameters: */
     302        ElementMatrix* Ke=NULL;
     303        int analysis_type;
     304        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     305
     306        /*Checks in debugging mode{{{2*/
     307        ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
     308        /*}}}*/
     309
     310        /*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
     311        switch(analysis_type){
     312                case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
     313                        Ke=CreateKMatrixDiagnosticMacAyeal();
     314                        break;
     315                case DiagnosticHutterAnalysisEnum:
     316                        Ke=CreateKMatrixDiagnosticHutter();
     317                        break;
     318                case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
     319                        Ke=CreateKMatrixSlope();
     320                        break;
     321                case PrognosticAnalysisEnum:
     322                        Ke=CreateKMatrixPrognostic();
     323                        break;
     324                case BalancedthicknessAnalysisEnum:
     325                        Ke=CreateKMatrixBalancedthickness();
     326                        break;
     327                case AdjointBalancedthicknessAnalysisEnum:
     328                        Ke=CreateKMatrixAdjointBalancedthickness();
     329                        break;
     330                case BalancedvelocitiesAnalysisEnum:
     331                        Ke=CreateKMatrixBalancedvelocities();
     332                        break;
     333                default:
     334                        ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
     335        }
     336
     337        /*Add to global matrix*/
     338        if(Ke){
     339                Ke->AddToGlobal(Kgg,Kff,Kfs);
     340                delete Ke;
     341        }
     342}
     343/*}}}*/
     344/*FUNCTION Tria::CreateKMatrixAdjointBalancedthickness {{{1*/
     345ElementMatrix* Tria::CreateKMatrixAdjointBalancedthickness(void){
     346
     347        ElementMatrix* Ke=NULL;
     348
     349        /*Get Element Matrix of the forward model*/
     350        switch(GetElementType()){
     351                case P1Enum:
     352                        Ke=CreateKMatrixBalancedthickness_CG();
     353                        break;
     354                case P1DGEnum:
     355                        Ke=CreateKMatrixBalancedthickness_DG();
     356                        break;
     357                default:
     358                        ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
     359        }
     360
     361        /*Transpose and return Ke*/
     362        Ke->Transpose();
     363        return Ke;
     364}
     365/*}}}*/
     366/*FUNCTION Tria::CreateKMatrixBalancedthickness {{{1*/
     367ElementMatrix* Tria::CreateKMatrixBalancedthickness(void){
     368
     369        switch(GetElementType()){
     370                case P1Enum:
     371                        return CreateKMatrixBalancedthickness_CG();
     372                case P1DGEnum:
     373                        return CreateKMatrixBalancedthickness_DG();
     374                default:
     375                        ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
     376        }
     377
     378}
     379/*}}}*/
     380/*FUNCTION Tria::CreateKMatrixBalancedthickness_CG {{{1*/
     381ElementMatrix* Tria::CreateKMatrixBalancedthickness_CG(void){
     382
     383        /*Constants*/
     384        const int    numdof=NDOF1*NUMVERTICES;
     385
     386        /*Intermediaries */
     387        int        artdiff;
     388        int        i,j,ig,dim;
     389        double     Jdettria ,vx,vy,dvxdx,dvydy;
     390        double     dvx[2],dvy[2];
     391        double     xyz_list[NUMVERTICES][3];
     392        double     L[NUMVERTICES];
     393        double     B[2][NUMVERTICES];
     394        double     Bprime[2][NUMVERTICES];
     395        double     K[2][2]                          = {0.0};
     396        double     KDL[2][2]                        = {0.0};
     397        double     DL[2][2]                         = {0.0};
     398        double     DLprime[2][2]                    = {0.0};
     399        double     DL_scalar;
     400        double     Ke_gg_gaussian[numdof][numdof]   = {0.0};
     401        double     Ke_gg_thickness1[numdof][numdof] = {0.0};
     402        double     Ke_gg_thickness2[numdof][numdof] = {0.0};
     403        GaussTria *gauss                            = NULL;
     404
     405        /*Initialize Element matrix and return if necessary*/
     406        if(IsOnWater()) return NULL;
     407        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     408
     409        /*Retrieve all Inputs and parameters: */
     410        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     411        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     412        this->parameters->FindParam(&dim,DimEnum);
     413        Input* vxaverage_input=NULL;
     414        Input* vyaverage_input=NULL;
     415        if(dim==2){
     416                vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
     417                vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
     418        }
     419        else{
     420                vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
     421                vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
     422        }
     423
     424        /*Create Artificial diffusivity once for all if requested*/
     425        if(artdiff){
     426                gauss=new GaussTria();
     427                gauss->GaussCenter();
     428                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     429                delete gauss;
     430
     431                vxaverage_input->GetParameterAverage(&vx);
     432                vyaverage_input->GetParameterAverage(&vy);
     433                K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(vx);
     434                K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(vy);
     435        }
     436
     437        /*Start looping on the number of gaussian points:*/
     438        gauss=new GaussTria(2);
     439        for (ig=gauss->begin();ig<gauss->end();ig++){
     440
     441                gauss->GaussPoint(ig);
     442
     443                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     444                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
     445                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
     446
     447                vxaverage_input->GetParameterValue(&vx,gauss);
     448                vyaverage_input->GetParameterValue(&vy,gauss);
     449                vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
     450                vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
     451
     452                dvxdx=dvx[0];
     453                dvydy=dvy[1];
     454                DL_scalar=gauss->weight*Jdettria;
     455
     456                DL[0][0]=DL_scalar*dvxdx;
     457                DL[1][1]=DL_scalar*dvydy;
     458
     459                DLprime[0][0]=DL_scalar*vx;
     460                DLprime[1][1]=DL_scalar*vy;
     461
     462                TripleMultiply( &B[0][0],2,numdof,1,
     463                                        &DL[0][0],2,2,0,
     464                                        &B[0][0],2,numdof,0,
     465                                        &Ke_gg_thickness1[0][0],0);
     466
     467                TripleMultiply( &B[0][0],2,numdof,1,
     468                                        &DLprime[0][0],2,2,0,
     469                                        &Bprime[0][0],2,numdof,0,
     470                                        &Ke_gg_thickness2[0][0],0);
     471
     472                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
     473                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
     474
     475                if(artdiff){
     476                        KDL[0][0]=DL_scalar*K[0][0];
     477                        KDL[1][1]=DL_scalar*K[1][1];
     478
     479                        TripleMultiply( &Bprime[0][0],2,numdof,1,
     480                                                &KDL[0][0],2,2,0,
     481                                                &Bprime[0][0],2,numdof,0,
     482                                                &Ke_gg_gaussian[0][0],0);
     483
     484                        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     485                }
     486        }
     487
     488        /*Clean up and return*/
     489        delete gauss;
     490        return Ke;
     491}
     492/*}}}*/
     493/*FUNCTION Tria::CreateKMatrixBalancedthickness_DG {{{1*/
     494ElementMatrix* Tria::CreateKMatrixBalancedthickness_DG(void){
     495
     496        /*Constants*/
     497        const int  numdof=NDOF1*NUMVERTICES;
     498
     499        /*Intermediaries*/
     500        int        i,j,ig,dim;
     501        double     vx,vy,Jdettria;
     502        double     xyz_list[NUMVERTICES][3];
     503        double     B[2][NUMVERTICES];
     504        double     Bprime[2][NUMVERTICES];
     505        double     DL[2][2]={0.0};
     506        double     DL_scalar;
     507        double     Ke_gg[numdof][numdof]={0.0};
     508        GaussTria  *gauss=NULL;
     509
     510        /*Initialize Element matrix and return if necessary*/
     511        if(IsOnWater()) return NULL;
     512        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     513
     514        /*Retrieve all inputs and parameters*/
     515        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     516        this->parameters->FindParam(&dim,DimEnum);
     517        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     518        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     519
     520        /*Start looping on the number of gaussian points:*/
     521        gauss=new GaussTria(2);
     522        for (ig=gauss->begin();ig<gauss->end();ig++){
     523
     524                gauss->GaussPoint(ig);
     525
     526                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     527                /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
     528                GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
     529                GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
     530
     531                vx_input->GetParameterValue(&vx,gauss);
     532                vy_input->GetParameterValue(&vy,gauss);
     533
     534                DL_scalar=-gauss->weight*Jdettria;
     535                DL[0][0]=DL_scalar*vx;
     536                DL[1][1]=DL_scalar*vy;
     537
     538                TripleMultiply( &B[0][0],2,numdof,1,
     539                                        &DL[0][0],2,2,0,
     540                                        &Bprime[0][0],2,numdof,0,
     541                                        &Ke_gg[0][0],0);
     542
     543                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
     544        }
     545
     546        /*Clean up and return*/
     547        delete gauss;
     548        return Ke;
     549}
     550/*}}}*/
     551/*FUNCTION Tria::CreateKMatrixBalancedvelocities {{{1*/
     552ElementMatrix* Tria::CreateKMatrixBalancedvelocities(void){
     553
     554        /*Constants*/
     555        const int    numdof=NDOF1*NUMVERTICES;
     556
     557        /*Intermediaries */
     558        int     artdiff;
     559        int     i,j,ig,dim;
     560        double  nx,ny,norm,Jdettria;
     561        double  dvx[2],dvy[2];
     562        double  vx,vy,dvxdx,dvydy;
     563        double  v_gauss[2]={0.0};
     564        double  surface_normal[3];
     565        double  surface_list[3];
     566        double  xyz_list[NUMVERTICES][3];
     567        double  B[2][NUMVERTICES];
     568        double  Bprime[2][NUMVERTICES];
     569        double  K[2][2]={0.0};
     570        double  KDL[2][2]={0.0};
     571        double  DLprime[2][2]={0.0};
     572        double  DL_scalar;
     573        double  Ke_gg_gaussian[numdof][numdof]   = {0.0};
     574        double  Ke_gg_velocities[numdof][numdof] = {0.0};
     575        GaussTria *gauss=NULL;
     576
     577        /*Initialize Element matrix and return if necessary*/
     578        if(IsOnWater()) return NULL;
     579        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     580
     581        /*Retrieve all inputs and parameters*/
     582        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     583        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     584        this->parameters->FindParam(&dim,DimEnum);
     585        Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
     586        Input* vxaverage_input=NULL;
     587        Input* vyaverage_input=NULL;
     588        if(dim==2){
     589                vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
     590                vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
     591        }
     592        else{
     593                vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
     594                vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
     595        }
     596
     597        /*Modify z so that it reflects the surface*/
     598        GetParameterListOnVertices(&surface_list[0],SurfaceEnum);
     599        for(i=0;i<NUMVERTICES;i++) xyz_list[i][2]=surface_list[i];
     600
     601        /*Get normal vector to the surface*/
     602        vxaverage_input->GetParameterAverage(&nx);
     603        vyaverage_input->GetParameterAverage(&ny);
     604        if(nx==0 && ny==0){
     605                SurfaceNormal(&surface_normal[0],xyz_list);
     606                nx=surface_normal[0];
     607                ny=surface_normal[1];
     608        }
     609        if(nx==0 && ny==0){
     610                nx=0; ny=1;
     611        }
     612        norm=pow( pow(nx,2)+pow(ny,2) , (double).5);
     613        nx=nx/norm; ny=ny/norm;
     614
     615        //Create Artificial diffusivity once for all if requested
     616        if(artdiff){
     617                gauss=new GaussTria();
     618                gauss->GaussCenter();
     619                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     620                delete gauss;
     621
     622                vxaverage_input->GetParameterAverage(&v_gauss[0]);
     623                vyaverage_input->GetParameterAverage(&v_gauss[1]);
     624                K[0][0]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]); //pow should be zero!!
     625                K[1][1]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
     626        }
     627
     628        /* Start  looping on the number of gaussian points: */
     629        gauss=new GaussTria(2);
     630        for (ig=gauss->begin();ig<gauss->end();ig++){
     631
     632                gauss->GaussPoint(ig);
     633
     634                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     635                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
     636                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
     637
     638                vxaverage_input->GetParameterValue(&vx,gauss);
     639                vyaverage_input->GetParameterValue(&vy,gauss);
     640                vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
     641                vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
     642
     643                dvxdx=dvx[0];
     644                dvydy=dvy[1];
     645                DL_scalar=gauss->weight*Jdettria;
     646
     647                DLprime[0][0]=DL_scalar*nx;
     648                DLprime[1][1]=DL_scalar*ny;
     649
     650                TripleMultiply( &B[0][0],2,numdof,1,
     651                                        &DLprime[0][0],2,2,0,
     652                                        &Bprime[0][0],2,numdof,0,
     653                                        &Ke_gg_velocities[0][0],0);
     654
     655                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_velocities[i][j];
     656
     657                if(artdiff){
     658                        KDL[0][0]=DL_scalar*K[0][0];
     659                        KDL[1][1]=DL_scalar*K[1][1];
     660
     661                        TripleMultiply( &Bprime[0][0],2,numdof,1,
     662                                                &KDL[0][0],2,2,0,
     663                                                &Bprime[0][0],2,numdof,0,
     664                                                &Ke_gg_gaussian[0][0],0);
     665
     666                        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     667                }
     668        }
     669
     670        /*Clean up and return*/
     671        delete gauss;
     672        return Ke;
     673}
     674/*}}}*/
     675/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyeal {{{1*/
     676ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyeal(void){
     677       
     678        /*compute all stiffness matrices for this element*/
     679        ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyealViscous();
     680        ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyealFriction();
     681        ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
     682
     683        /*clean-up and return*/
     684        delete Ke1;
     685        delete Ke2;
     686        return Ke;
     687
     688}
     689/*}}}*/
     690/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealViscous{{{1*/
     691ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealViscous(void){
     692
     693        /*Constants*/
     694        const int  numdof=NDOF2*NUMVERTICES;
     695
     696        /*Intermediaries*/
     697        int        i,j,ig;
     698        double     xyz_list[NUMVERTICES][3];
     699        double     viscosity,newviscosity,oldviscosity;
     700        double     viscosity_overshoot,thickness,Jdet;
     701        double     epsilon[3],oldepsilon[3];    /* epsilon=[exx,eyy,exy];    */
     702        double     B[3][numdof];
     703        double     Bprime[3][numdof];
     704        double     D[3][3]   = {0.0};
     705        double     D_scalar;
     706        double     Ke_g[numdof][numdof];
     707        GaussTria *gauss = NULL;
     708
     709        /*Initialize Element matrix and return if necessary*/
     710        if(IsOnWater()) return NULL;
     711        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
     712
     713        /*Retrieve all inputs and parameters*/
     714        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     715        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     716        Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
     717        Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
     718        Input* vxold_input=inputs->GetInput(VxOldEnum);         ISSMASSERT(vxold_input);
     719        Input* vyold_input=inputs->GetInput(VyOldEnum);         ISSMASSERT(vyold_input);
     720        this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
     721
     722        /* Start  looping on the number of gaussian points: */
     723        gauss=new GaussTria(2);
     724        for (ig=gauss->begin();ig<gauss->end();ig++){
     725
     726                gauss->GaussPoint(ig);
     727
     728                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     729                GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss);
     730                GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss);
     731
     732                this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
     733                this->GetStrainRate2d(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
     734                matice->GetViscosity2d(&viscosity, &epsilon[0]);
     735                matice->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
     736                thickness_input->GetParameterValue(&thickness, gauss);
     737
     738                newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
     739                D_scalar=2*newviscosity*thickness*gauss->weight*Jdet;
     740                for (i=0;i<3;i++) D[i][i]=D_scalar;
     741
     742                TripleMultiply(&B[0][0],3,numdof,1,
     743                                        &D[0][0],3,3,0,
     744                                        &Bprime[0][0],3,numdof,0,
     745                                        &Ke_g[0][0],0);
     746
     747                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
     748        }
     749
     750        /*Clean up and return*/
     751        delete gauss;
     752        return Ke;
     753}
     754/*}}}*/
     755/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealFriction {{{1*/
     756ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealFriction(void){
     757
     758        /*Constants*/
     759        const int  numdof=NDOF2*NUMVERTICES;
     760
     761        /*Intermediaries*/
     762        int        i,j,ig;
     763        int        analysis_type,drag_type;
     764        double     MAXSLOPE  = .06; // 6 %
     765        double     MOUNTAINKEXPONENT = 10;
     766        double     slope_magnitude,alpha2;
     767        double     Jdet;
     768        double     L[2][numdof];
     769        double     DL[2][2]  = {{ 0,0 },{0,0}};
     770        double     Ke_g[numdof][numdof];
     771        double     DL_scalar;
     772        double     slope[2]  = {0.0,0.0};
     773        double     xyz_list[NUMVERTICES][3];
     774        Friction  *friction = NULL;
     775        GaussTria *gauss    = NULL;
     776
     777        /*Initialize Element matrix and return if necessary*/
     778        if(IsOnWater() || IsOnShelf()) return NULL;
     779        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
     780
     781        /*Retrieve all inputs and parameters*/
     782        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     783        Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
     784        Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
     785        Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
     786        Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
     787        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     788        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     789
     790        /*build friction object, used later on: */
     791        if (drag_type!=2) ISSMERROR(" non-viscous friction not supported yet!");
     792        friction=new Friction("2d",inputs,matpar,analysis_type);
     793
     794        /* Start  looping on the number of gaussian points: */
     795        gauss=new GaussTria(2);
     796        for (ig=gauss->begin();ig<gauss->end();ig++){
     797
     798                gauss->GaussPoint(ig);
     799
     800                // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
     801                //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
     802                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     803                slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
     804                if(slope_magnitude>MAXSLOPE) alpha2=pow((double)10,MOUNTAINKEXPONENT);
     805                else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
     806
     807                GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
     808                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     809                DL_scalar=alpha2*gauss->weight*Jdet;
     810                for (i=0;i<2;i++) DL[i][i]=DL_scalar;
     811               
     812                TripleMultiply( &L[0][0],2,numdof,1,
     813                                        &DL[0][0],2,2,0,
     814                                        &L[0][0],2,numdof,0,
     815                                        &Ke_g[0][0],0);
     816
     817                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
     818        }
     819
     820        /*Clean up and return*/
     821        delete gauss;
     822        delete friction;
     823        return Ke;
     824}
     825/*}}}*/
     826/*FUNCTION Tria::CreateKMatrixCouplingMacAyealPattynFriction {{{1*/
     827ElementMatrix* Tria::CreateKMatrixCouplingMacAyealPattynFriction(void){
     828
     829        /*Constants*/
     830        const int numdof        = NDOF2 *NUMVERTICES;
     831        const int numdoftotal   = NDOF4 *NUMVERTICES;
     832       
     833        /*Intermediaries */
     834        int       i,j,ig,analysis_type,drag_type;
     835        double    Jdet,slope_magnitude,alpha2;
     836        double    xyz_list[NUMVERTICES][3];
     837        double    slope[2]={0.0,0.0};
     838        double    MAXSLOPE=.06; // 6 %
     839        double    MOUNTAINKEXPONENT=10;
     840        double    L[2][numdof];
     841        double    DL[2][2]                  ={{ 0,0 },{0,0}}; //for basal drag
     842        double    DL_scalar;
     843        double    Ke_gg[numdof][numdof]     ={0.0};
     844        double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
     845        Friction  *friction = NULL;
     846        GaussTria *gauss=NULL;
     847
     848        /*Initialize Element matrix and return if necessary*/
     849        if(IsOnWater() || IsOnShelf()) return NULL;
     850        ElementMatrix* Ke1=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
     851        ElementMatrix* Ke2=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
     852        ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
     853        delete Ke1; delete Ke2;
     854
     855        /*retrieve inputs :*/
     856        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     857        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     858        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     859        Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
     860        Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
     861        Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
     862        Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
     863
     864        /*build friction object, used later on: */
     865        if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
     866        friction=new Friction("2d",inputs,matpar,analysis_type);
     867
     868        /* Start  looping on the number of gaussian points: */
     869        gauss=new GaussTria(2);
     870        for (ig=gauss->begin();ig<gauss->end();ig++){
     871
     872                gauss->GaussPoint(ig);
     873
     874                /*Friction: */
     875                friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
     876
     877                // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
     878                //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
     879                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     880                slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
     881
     882                if (slope_magnitude>MAXSLOPE){
     883                        alpha2=pow((double)10,MOUNTAINKEXPONENT);
     884                }
     885
     886                /* Get Jacobian determinant: */
     887                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     888
     889                /*Get L matrix: */
     890                GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
     891
     892               
     893                DL_scalar=alpha2*gauss->weight*Jdet;
     894                for (i=0;i<2;i++){
     895                        DL[i][i]=DL_scalar;
     896                }
     897               
     898                /*  Do the triple producte tL*D*L: */
     899                TripleMultiply( &L[0][0],2,numdof,1,
     900                                        &DL[0][0],2,2,0,
     901                                        &L[0][0],2,numdof,0,
     902                                        &Ke_gg_gaussian[0][0],0);
     903
     904                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
     905        }
     906
     907        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdoftotal+(numdof+j)]+=Ke_gg[i][j];
     908        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[(i+numdof)*numdoftotal+j]+=Ke_gg[i][j];
     909
     910        /*Clean up and return*/
     911        delete gauss;
     912        delete friction;
     913        return Ke;
     914}       
     915/*}}}*/
     916/*FUNCTION Tria::CreateKMatrixDiagnosticPattynFriction {{{1*/
     917ElementMatrix* Tria::CreateKMatrixDiagnosticPattynFriction(void){
     918
     919        /*Constants*/
     920        const int numdof   = NDOF2*NUMVERTICES;
     921       
     922        /*Intermediaries */
     923        int       i,j,ig;
     924        int       analysis_type,drag_type;
     925        double    xyz_list[NUMVERTICES][3];
     926        double    slope_magnitude,alpha2,Jdet;
     927        double    slope[2]={0.0,0.0};
     928        double    MAXSLOPE=.06; // 6 %
     929        double    MOUNTAINKEXPONENT=10;
     930        double    L[2][numdof];
     931        double    DL[2][2]={{ 0,0 },{0,0}}; //for basal drag
     932        double    DL_scalar;
     933        double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
     934        Friction  *friction = NULL;
     935        GaussTria *gauss=NULL;
     936
     937        /*Initialize Element matrix and return if necessary*/
     938        if(IsOnWater() || IsOnShelf()) return NULL;
     939        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
     940
     941        /*Retrieve all inputs and parameters*/
     942        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     943        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     944        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     945        Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
     946        Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
     947        Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
     948        Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
     949
     950        /*build friction object, used later on: */
     951        if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
     952        friction=new Friction("2d",inputs,matpar,analysis_type);
     953
     954        /* Start  looping on the number of gaussian points: */
     955        gauss=new GaussTria(2);
     956        for (ig=gauss->begin();ig<gauss->end();ig++){
     957
     958                gauss->GaussPoint(ig);
     959
     960                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     961                GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
     962
     963                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     964                friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum); // TO UNCOMMENT
     965                slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
     966
     967                // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
     968                //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
     969                if (slope_magnitude>MAXSLOPE){
     970                        alpha2=pow((double)10,MOUNTAINKEXPONENT);
     971                }
     972               
     973                DL_scalar=alpha2*gauss->weight*Jdet;
     974                for (i=0;i<2;i++) DL[i][i]=DL_scalar;
     975               
     976                TripleMultiply( &L[0][0],2,numdof,1,
     977                                        &DL[0][0],2,2,0,
     978                                        &L[0][0],2,numdof,0,
     979                                        &Ke_gg_gaussian[0][0],0);
     980
     981                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     982        }
     983
     984        /*Clean up and return*/
     985        delete gauss;
     986        delete friction;
     987        return Ke;
     988}       
     989/*}}}*/
     990/*FUNCTION Tria::CreateKMatrixDiagnosticHutter{{{1*/
     991ElementMatrix* Tria::CreateKMatrixDiagnosticHutter(void){
     992
     993        /*Intermediaries*/
     994        const int numdof=NUMVERTICES*NDOF2;
     995        int    i,connectivity;
     996
     997        /*Initialize Element matrix and return if necessary*/
     998        if(IsOnWater()) return NULL;
     999        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1000
     1001        /*Create Element matrix*/
     1002        for(i=0;i<NUMVERTICES;i++){
     1003                connectivity=nodes[i]->GetConnectivity();
     1004                Ke->values[(2*i)*numdof  +(2*i)  ]=1/(double)connectivity;
     1005                Ke->values[(2*i+1)*numdof+(2*i+1)]=1/(double)connectivity;
     1006        }
     1007
     1008        /*Clean up and return*/
     1009        return Ke;
     1010}
     1011/*}}}*/
     1012/*FUNCTION Tria::CreateKMatrixDiagnosticVertSurface {{{1*/
     1013ElementMatrix* Tria::CreateKMatrixDiagnosticVertSurface(void){
     1014
     1015        /*Constants*/
     1016        const int numdof=NDOF1*NUMVERTICES;
     1017
     1018        /*Intermediaries */
     1019        int       i,j,ig;
     1020        double    xyz_list[NUMVERTICES][3];
     1021        double    surface_normal[3];
     1022        double    Jdet,DL_scalar;
     1023        double    L[3];
     1024        GaussTria *gauss=NULL;
     1025        double Ke_g[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
     1026
     1027        /*Initialize Element matrix and return if necessary*/
     1028        if(IsOnWater()) return NULL;
     1029        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1030
     1031        /*Retrieve all inputs and parameters*/
     1032        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1033        SurfaceNormal(&surface_normal[0],xyz_list);
     1034
     1035        /* Start  looping on the number of gaussian points: */
     1036        gauss=new GaussTria(2);
     1037        for (ig=gauss->begin();ig<gauss->end();ig++){
     1038
     1039                gauss->GaussPoint(ig);
     1040
     1041                GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
     1042                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1043
     1044                /**********************Do not forget the sign**********************************/
     1045                DL_scalar=- gauss->weight*Jdet*surface_normal[2];
     1046                /******************************************************************************/
     1047
     1048                TripleMultiply( L,1,3,1,
     1049                                        &DL_scalar,1,1,0,
     1050                                        L,1,3,0,
     1051                                        &Ke_g[0][0],0);
     1052
     1053                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
     1054        }
     1055
     1056        /*Clean up and return*/
     1057        delete gauss;
     1058        return Ke;
     1059}
     1060/*}}}*/
     1061/*FUNCTION Tria::CreateKMatrixMelting {{{1*/
     1062ElementMatrix* Tria::CreateKMatrixMelting(void){
     1063
     1064        /*Constants*/
     1065        const int  numdof=NUMVERTICES*NDOF1;
     1066
     1067        /*Intermediaries */
     1068        int        i,j,ig;
     1069        double     heatcapacity,latentheat;
     1070        double     Jdet,D_scalar;
     1071        double     xyz_list[NUMVERTICES][3];
     1072        double     L[3];
     1073        double     Ke_gaussian[numdof][numdof]={0.0};
     1074        GaussTria *gauss=NULL;
     1075
     1076        /*Initialize Element matrix and return if necessary*/
     1077        if(IsOnWater()) return NULL;
     1078        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1079
     1080        /*Retrieve all inputs and parameters*/
     1081        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1082        latentheat=matpar->GetLatentHeat();
     1083        heatcapacity=matpar->GetHeatCapacity();
     1084
     1085        /* Start looping on the number of gauss  (nodes on the bedrock) */
     1086        gauss=new GaussTria(2);
     1087        for (ig=gauss->begin();ig<gauss->end();ig++){
     1088
     1089                gauss->GaussPoint(ig);
     1090
     1091                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1092                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
     1093
     1094                D_scalar=latentheat/heatcapacity*gauss->weight*Jdet;
     1095
     1096                TripleMultiply(&L[0],numdof,1,0,
     1097                                        &D_scalar,1,1,0,
     1098                                        &L[0],1,numdof,0,
     1099                                        &Ke_gaussian[0][0],0);
     1100
     1101                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
     1102        }
     1103
     1104        /*Clean up and return*/
     1105        delete gauss;
     1106        return Ke;
     1107}
     1108/*}}}*/
     1109/*FUNCTION Tria::CreateKMatrixPrognostic {{{1*/
     1110ElementMatrix* Tria::CreateKMatrixPrognostic(void){
     1111
     1112        switch(GetElementType()){
     1113                case P1Enum:
     1114                        return CreateKMatrixPrognostic_CG();
     1115                case P1DGEnum:
     1116                        return CreateKMatrixPrognostic_DG();
     1117                default:
     1118                        ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
     1119        }
     1120
     1121}
     1122/*}}}*/
     1123/*FUNCTION Tria::CreateKMatrixPrognostic_CG {{{1*/
     1124ElementMatrix* Tria::CreateKMatrixPrognostic_CG(void){
     1125
     1126        /*Constants*/
     1127        const int    numdof=NDOF1*NUMVERTICES;
     1128
     1129        /*Intermediaries */
     1130        int        artdiff;
     1131        int        i,j,ig,dim;
     1132        double     Jdettria,DL_scalar,dt;
     1133        double     vx,vy,dvxdx,dvydy;
     1134        double     dvx[2],dvy[2];
     1135        double     v_gauss[2]={0.0};
     1136        double     xyz_list[NUMVERTICES][3];
     1137        double     L[NUMVERTICES];
     1138        double     B[2][NUMVERTICES];
     1139        double     Bprime[2][NUMVERTICES];
     1140        double     K[2][2]                        ={0.0};
     1141        double     KDL[2][2]                      ={0.0};
     1142        double     DL[2][2]                        ={0.0};
     1143        double     DLprime[2][2]                   ={0.0};
     1144        double     Ke_gg_gaussian[numdof][numdof]  ={0.0};
     1145        double     Ke_gg_thickness1[numdof][numdof]={0.0};
     1146        double     Ke_gg_thickness2[numdof][numdof]={0.0};
     1147        GaussTria *gauss=NULL;
     1148
     1149        /*Initialize Element matrix and return if necessary*/
     1150        if(IsOnWater()) return NULL;
     1151        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1152
     1153        /*Retrieve all inputs and parameters*/
     1154        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1155        this->inputs->GetParameterValue(&dt,DtEnum);
     1156        this->parameters->FindParam(&dim,DimEnum);
     1157        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     1158        Input* vxaverage_input=NULL;
     1159        Input* vyaverage_input=NULL;
     1160        if(dim==2){
     1161                vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
     1162                vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
     1163        }
     1164        else{
     1165                vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
     1166                vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
     1167        }
     1168
     1169        //Create Artificial diffusivity once for all if requested
     1170        if(artdiff){
     1171                gauss=new GaussTria();
     1172                gauss->GaussCenter();
     1173                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1174                delete gauss;
     1175
     1176                vxaverage_input->GetParameterAverage(&v_gauss[0]);
     1177                vyaverage_input->GetParameterAverage(&v_gauss[1]);
     1178
     1179                K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]);
     1180                K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
     1181        }
     1182
     1183        /* Start  looping on the number of gaussian points: */
     1184        gauss=new GaussTria(2);
     1185        for (ig=gauss->begin();ig<gauss->end();ig++){
     1186
     1187                gauss->GaussPoint(ig);
     1188
     1189                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1190                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1191
     1192                vxaverage_input->GetParameterValue(&vx,gauss);
     1193                vyaverage_input->GetParameterValue(&vy,gauss);
     1194                vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
     1195                vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
     1196
     1197                DL_scalar=gauss->weight*Jdettria;
     1198
     1199                TripleMultiply( &L[0],1,numdof,1,
     1200                                        &DL_scalar,1,1,0,
     1201                                        &L[0],1,numdof,0,
     1202                                        &Ke_gg_gaussian[0][0],0);
     1203
     1204                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
     1205                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
     1206
     1207                dvxdx=dvx[0];
     1208                dvydy=dvy[1];
     1209                DL_scalar=dt*gauss->weight*Jdettria;
     1210
     1211                DL[0][0]=DL_scalar*dvxdx;
     1212                DL[1][1]=DL_scalar*dvydy;
     1213                DLprime[0][0]=DL_scalar*vx;
     1214                DLprime[1][1]=DL_scalar*vy;
     1215
     1216                TripleMultiply( &B[0][0],2,numdof,1,
     1217                                        &DL[0][0],2,2,0,
     1218                                        &B[0][0],2,numdof,0,
     1219                                        &Ke_gg_thickness1[0][0],0);
     1220
     1221                TripleMultiply( &B[0][0],2,numdof,1,
     1222                                        &DLprime[0][0],2,2,0,
     1223                                        &Bprime[0][0],2,numdof,0,
     1224                                        &Ke_gg_thickness2[0][0],0);
     1225
     1226                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     1227                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
     1228                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
     1229
     1230                if(artdiff){
     1231                        KDL[0][0]=DL_scalar*K[0][0];
     1232                        KDL[1][1]=DL_scalar*K[1][1];
     1233
     1234                        TripleMultiply( &Bprime[0][0],2,numdof,1,
     1235                                                &KDL[0][0],2,2,0,
     1236                                                &Bprime[0][0],2,numdof,0,
     1237                                                &Ke_gg_gaussian[0][0],0);
     1238
     1239                        for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
     1240                }
     1241        }
     1242
     1243        /*Clean up and return*/
     1244        delete gauss;
     1245        return Ke;
     1246}
     1247/*}}}*/
     1248/*FUNCTION Tria::CreateKMatrixPrognostic_DG {{{1*/
     1249ElementMatrix* Tria::CreateKMatrixPrognostic_DG(void){
     1250
     1251        /*Constants*/
     1252        const int    numdof=NDOF1*NUMVERTICES;
     1253
     1254        /*Intermediaries */
     1255        int        i,j,ig,dim;
     1256        double     xyz_list[NUMVERTICES][3];
     1257        double     Jdettria,dt,vx,vy;
     1258        double     L[NUMVERTICES];
     1259        double     B[2][NUMVERTICES];
     1260        double     Bprime[2][NUMVERTICES];
     1261        double     DL[2][2]={0.0};
     1262        double     DLprime[2][2]={0.0};
     1263        double     DL_scalar;
     1264        double     Ke_gg1[numdof][numdof]={0.0};
     1265        double     Ke_gg2[numdof][numdof]={0.0};
     1266        GaussTria  *gauss=NULL;
     1267
     1268        /*Initialize Element matrix and return if necessary*/
     1269        if(IsOnWater()) return NULL;
     1270        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1271
     1272        /*Retrieve all inputs and parameters*/
     1273        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1274        this->inputs->GetParameterValue(&dt,DtEnum);
     1275        this->parameters->FindParam(&dim,DimEnum);
     1276        Input* vxaverage_input=NULL;
     1277        Input* vyaverage_input=NULL;
     1278        if(dim==2){
     1279                vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
     1280                vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
     1281        }
     1282        else{
     1283                vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
     1284                vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
     1285        }
     1286
     1287        /* Start  looping on the number of gaussian points: */
     1288        gauss=new GaussTria(2);
     1289        for (ig=gauss->begin();ig<gauss->end();ig++){
     1290
     1291                gauss->GaussPoint(ig);
     1292
     1293                vxaverage_input->GetParameterValue(&vx,gauss);
     1294                vyaverage_input->GetParameterValue(&vy,gauss);
     1295
     1296                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1297                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1298
     1299                DL_scalar=gauss->weight*Jdettria;
     1300
     1301                TripleMultiply( &L[0],1,numdof,1,
     1302                                        &DL_scalar,1,1,0,
     1303                                        &L[0],1,numdof,0,
     1304                                        &Ke_gg1[0][0],0);
     1305
     1306                /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
     1307                GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
     1308                GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
     1309
     1310                DL_scalar=-dt*gauss->weight*Jdettria;
     1311
     1312                DLprime[0][0]=DL_scalar*vx;
     1313                DLprime[1][1]=DL_scalar*vy;
     1314
     1315                TripleMultiply( &B[0][0],2,numdof,1,
     1316                                        &DLprime[0][0],2,2,0,
     1317                                        &Bprime[0][0],2,numdof,0,
     1318                                        &Ke_gg2[0][0],0);
     1319
     1320                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg1[i][j];
     1321                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg2[i][j];
     1322        }
     1323
     1324        /*Clean up and return*/
     1325        delete gauss;
     1326        return Ke;
     1327}
     1328/*}}}*/
     1329/*FUNCTION Tria::CreateKMatrixSlope {{{1*/
     1330ElementMatrix* Tria::CreateKMatrixSlope(void){
     1331
     1332        /*constants: */
     1333        const int    numdof=NDOF1*NUMVERTICES;
     1334
     1335        /* Intermediaries */
     1336        int        i,j,ig;
     1337        double     DL_scalar,Jdet;
     1338        double     xyz_list[NUMVERTICES][3];
     1339        double     L[1][3];
     1340        double     Ke_g[numdof][numdof];
     1341        GaussTria *gauss = NULL;
     1342
     1343        /*Initialize Element matrix and return if necessary*/
     1344        if(IsOnWater()) return NULL;
     1345        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1346
     1347        GetVerticesCoordinates(&xyz_list[0][0],nodes,NUMVERTICES);
     1348
     1349        /* Start looping on the number of gaussian points: */
     1350        gauss=new GaussTria(2);
     1351        for (ig=gauss->begin();ig<gauss->end();ig++){
     1352
     1353                gauss->GaussPoint(ig);
     1354               
     1355                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     1356                DL_scalar=gauss->weight*Jdet;
     1357
     1358                GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
     1359
     1360                TripleMultiply(&L[0][0],1,3,1,
     1361                                        &DL_scalar,1,1,0,
     1362                                        &L[0][0],1,3,0,
     1363                                        &Ke_g[0][0],0);
     1364
     1365                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
     1366        }
     1367
     1368        /*Clean up and return*/
     1369        delete gauss;
     1370        return Ke;
     1371}
     1372/*}}}*/
     1373/*FUNCTION Tria::CreateKMatrixThermal {{{1*/
     1374ElementMatrix* Tria::CreateKMatrixThermal(void){
     1375
     1376        /*Constants*/
     1377        const int    numdof=NDOF1*NUMVERTICES;
     1378
     1379        /*Intermediaries */
     1380        int       i,j,ig;
     1381        double    mixed_layer_capacity,thermal_exchange_velocity;
     1382        double    rho_ice,rho_water,heatcapacity;
     1383        double    Jdet,dt;
     1384        double    xyz_list[NUMVERTICES][3];
     1385        double    l1l2l3[NUMVERTICES];
     1386        double    D_scalar;
     1387        double    Ke_gaussian[numdof][numdof]={0.0};
     1388        GaussTria *gauss=NULL;
     1389
     1390        /*Initialize Element matrix and return if necessary*/
     1391        if(IsOnWater() || !IsOnShelf()) return NULL;
     1392        ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
     1393
     1394        /*Retrieve all inputs and parameters*/
     1395        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1396        this->inputs->GetParameterValue(&dt,DtEnum);
     1397        mixed_layer_capacity=matpar->GetMixedLayerCapacity();
     1398        thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
     1399        rho_water=matpar->GetRhoWater();
     1400        rho_ice=matpar->GetRhoIce();
     1401        heatcapacity=matpar->GetHeatCapacity();
     1402
     1403        /* Start looping on the number of gauss (nodes on the bedrock) */
     1404        gauss=new GaussTria(2);
     1405        for (ig=gauss->begin();ig<gauss->end();ig++){
     1406
     1407                gauss->GaussPoint(ig);
     1408               
     1409                GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
     1410                GetNodalFunctions(&l1l2l3[0], gauss);
     1411                               
     1412                D_scalar=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(heatcapacity*rho_ice);
     1413                if(dt) D_scalar=dt*D_scalar;
     1414
     1415                TripleMultiply(&l1l2l3[0],numdof,1,0,
     1416                                        &D_scalar,1,1,0,
     1417                                        &l1l2l3[0],1,numdof,0,
     1418                                        &Ke_gaussian[0][0],0);
     1419
     1420                for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
     1421        }
     1422       
     1423        /*Clean up and return*/
     1424        delete gauss;
     1425        return Ke;
     1426}
     1427/*}}}*/
     1428/*FUNCTION Tria::CreatePVector {{{1*/
     1429void  Tria::CreatePVector(Vec pg, Vec pf){
     1430
     1431        /*retrive parameters: */
     1432        ElementVector* pe=NULL;
     1433        int analysis_type;
     1434        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     1435
     1436        /*asserts: {{{*/
     1437        /*if debugging mode, check that all pointers exist*/
     1438        ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
     1439        /*}}}*/
     1440
     1441        /*Just branch to the correct load generator, according to the type of analysis we are carrying out: */
     1442        switch(analysis_type){
     1443                case DiagnosticHorizAnalysisEnum:
     1444                        pe=CreatePVectorDiagnosticMacAyeal();
     1445                        break;
     1446                case AdjointHorizAnalysisEnum:
     1447                        pe=CreatePVectorAdjointHoriz();
     1448                        break;
     1449                case DiagnosticHutterAnalysisEnum:
     1450                        pe=CreatePVectorDiagnosticHutter();
     1451                        break;
     1452                case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
     1453                        pe=CreatePVectorSlope();
     1454                        break;
     1455                case PrognosticAnalysisEnum:
     1456                        pe=CreatePVectorPrognostic();
     1457                        break;
     1458                case BalancedthicknessAnalysisEnum:
     1459                        pe=CreatePVectorBalancedthickness();
     1460                        break;
     1461                case AdjointBalancedthicknessAnalysisEnum:
     1462                        pe=CreatePVectorAdjointBalancedthickness();
     1463                        break;
     1464                case BalancedvelocitiesAnalysisEnum:
     1465                        pe=CreatePVectorBalancedvelocities();
     1466                        break;
     1467                default:
     1468                        ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
     1469        }
     1470
     1471        /*Add to global Vector*/
     1472        if(pe){
     1473                pe->AddToGlobal(pg,pf);
     1474                delete pe;
     1475        }
     1476}
     1477/*}}}*/
     1478/*FUNCTION Tria::CreatePVectorBalancedthickness{{{1*/
     1479ElementVector* Tria::CreatePVectorBalancedthickness(void){
     1480
     1481        switch(GetElementType()){
     1482                case P1Enum:
     1483                        return CreatePVectorBalancedthickness_CG();
     1484                        break;
     1485                case P1DGEnum:
     1486                        return CreatePVectorBalancedthickness_DG();
     1487                default:
     1488                        ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
     1489        }
     1490}
     1491/*}}}*/
     1492/*FUNCTION Tria::CreatePVectorBalancedthickness_CG{{{1*/
     1493ElementVector* Tria::CreatePVectorBalancedthickness_CG(void){
     1494
     1495        /*Constants*/
     1496        const int    numdof=NDOF1*NUMVERTICES;
     1497       
     1498        /*Intermediaries */
     1499        int        i,j,ig;
     1500        double     xyz_list[NUMVERTICES][3];
     1501        double     dhdt_g,melting_g,accumulation_g,Jdettria;
     1502        double     L[NUMVERTICES];
     1503        GaussTria* gauss=NULL;
     1504
     1505        /*Initialize Element vector and return if necessary*/
     1506        if(IsOnWater()) return NULL;
     1507        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1508
     1509        /*Retrieve all inputs and parameters*/
     1510        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1511        Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
     1512        Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
     1513        Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
     1514       
     1515        /* Start  looping on the number of gaussian points: */
     1516        gauss=new GaussTria(2);
     1517        for(ig=gauss->begin();ig<gauss->end();ig++){
     1518
     1519                gauss->GaussPoint(ig);
     1520
     1521                accumulation_input->GetParameterValue(&accumulation_g,gauss);
     1522                melting_input->GetParameterValue(&melting_g,gauss);
     1523                dhdt_input->GetParameterValue(&dhdt_g,gauss);
     1524
     1525                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1526                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1527
     1528                for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
     1529        }
     1530
     1531        /*Clean up and return*/
     1532        delete gauss;
     1533        return pe;
     1534}
     1535/*}}}*/
     1536/*FUNCTION Tria::CreatePVectorBalancedthickness_DG {{{1*/
     1537ElementVector* Tria::CreatePVectorBalancedthickness_DG(void){
     1538
     1539        /*Constants*/
     1540        const int    numdof=NDOF1*NUMVERTICES;
     1541
     1542        /*Intermediaries */
     1543        int        i,j,ig;
     1544        double     xyz_list[NUMVERTICES][3];
     1545        double     melting_g,accumulation_g,dhdt_g,Jdettria;
     1546        double     L[NUMVERTICES];
     1547        GaussTria* gauss=NULL;
     1548
     1549        /*Initialize Element vector and return if necessary*/
     1550        if(IsOnWater()) return NULL;
     1551        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1552
     1553        /*Retrieve all inputs and parameters*/
     1554        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1555        Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
     1556        Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
     1557        Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
     1558
     1559        /* Start  looping on the number of gaussian points: */
     1560        gauss=new GaussTria(2);
     1561        for(ig=gauss->begin();ig<gauss->end();ig++){
     1562
     1563                gauss->GaussPoint(ig);
     1564
     1565                accumulation_input->GetParameterValue(&accumulation_g,gauss);
     1566                melting_input->GetParameterValue(&melting_g,gauss);
     1567                dhdt_input->GetParameterValue(&dhdt_g,gauss);
     1568
     1569                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1570                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1571
     1572                for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
     1573        }
     1574
     1575        /*Clean up and return*/
     1576        delete gauss;
     1577        return pe;
     1578}
     1579/*}}}*/
     1580/*FUNCTION Tria::CreatePVectorBalancedvelocities {{{1*/
     1581ElementVector* Tria::CreatePVectorBalancedvelocities(void){
     1582
     1583        /*Constants*/
     1584        const int    numdof=NDOF1*NUMVERTICES;
     1585
     1586        /*Intermediaries */
     1587        int        i,j,ig;
     1588        double     xyz_list[NUMVERTICES][3];
     1589        double     Jdettria,accumulation_g,melting_g;
     1590        double     L[NUMVERTICES];
     1591        GaussTria* gauss=NULL;
     1592
     1593        /*Initialize Element vector and return if necessary*/
     1594        if(IsOnWater()) return NULL;
     1595        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1596
     1597        /*Retrieve all inputs and parameters*/
     1598        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1599        Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
     1600        Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
     1601
     1602        /* Start  looping on the number of gaussian points: */
     1603        gauss=new GaussTria(2);
     1604        for(ig=gauss->begin();ig<gauss->end();ig++){
     1605
     1606                gauss->GaussPoint(ig);
     1607
     1608                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     1609                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1610
     1611                accumulation_input->GetParameterValue(&accumulation_g,gauss);
     1612                melting_input->GetParameterValue(&melting_g,gauss);
     1613
     1614                for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g)*L[i];
     1615        }
     1616
     1617        /*Clean up and return*/
     1618        delete gauss;
     1619        return pe;
     1620}
     1621/*}}}*/
     1622/*FUNCTION Tria::CreatePVectorDiagnosticBaseVert {{{1*/
     1623ElementVector* Tria::CreatePVectorDiagnosticBaseVert(void){
     1624
     1625        /*Constants*/
     1626        const int    numdof=NDOF1*NUMVERTICES;
     1627
     1628        /*Intermediaries */
     1629        int        i,j,ig;
     1630        int        approximation;
     1631        double     xyz_list[NUMVERTICES][3];
     1632        double     Jdet;
     1633        double     vx,vy,vz,dbdx,dbdy,meltingvalue;
     1634        double     slope[2];
     1635        double     L[NUMVERTICES];
     1636        GaussTria* gauss=NULL;
     1637
     1638        /*Initialize Element vector and return if necessary*/
     1639        if(IsOnWater()) return NULL;
     1640        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1641
     1642        /*Retrieve all inputs and parameters*/
     1643        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1644        inputs->GetParameterValue(&approximation,ApproximationEnum);
     1645        Input* bed_input=inputs->GetInput(BedEnum);             ISSMASSERT(bed_input);
     1646        Input* melting_input=inputs->GetInput(MeltingRateEnum); ISSMASSERT(melting_input);
     1647        Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
     1648        Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
     1649        Input* vzstokes_input=NULL;
     1650        if(approximation==PattynStokesApproximationEnum){
     1651                vzstokes_input=inputs->GetInput(VzStokesEnum);       ISSMASSERT(vzstokes_input);
     1652        }
     1653
     1654        /* Start  looping on the number of gaussian points: */
     1655        gauss=new GaussTria(2);
     1656        for(ig=gauss->begin();ig<gauss->end();ig++){
     1657
     1658                gauss->GaussPoint(ig);
     1659
     1660                melting_input->GetParameterValue(&meltingvalue, gauss);
     1661                bed_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     1662                vx_input->GetParameterValue(&vx, gauss);
     1663                vy_input->GetParameterValue(&vy, gauss);
     1664                if(approximation==PattynStokesApproximationEnum){
     1665                        vzstokes_input->GetParameterValue(&vz, gauss);
     1666                }
     1667                else vz=0;
     1668
     1669                dbdx=slope[0];
     1670                dbdy=slope[1];
     1671
     1672                GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
     1673                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     1674
     1675                for(i=0;i<numdof;i++) pe->values[i]+=-Jdet*gauss->weight*(vx*dbdx+vy*dbdy-vz-meltingvalue)*L[i];
     1676        }
     1677
     1678        /*Clean up and return*/
     1679        delete gauss;
     1680        return pe;
     1681}
     1682/*}}}*/
     1683/*FUNCTION Tria::CreatePVectorDiagnosticMacAyeal {{{1*/
     1684ElementVector* Tria::CreatePVectorDiagnosticMacAyeal(){
     1685
     1686        /*Constants*/
     1687        const int    numdof=NDOF2*NUMVERTICES;
     1688
     1689        /*Intermediaries */
     1690        int            i,j,ig,drag_type;
     1691        double         plastic_stress,driving_stress_baseline,thickness;
     1692        double         Jdet;
     1693        double         xyz_list[NUMVERTICES][3];
     1694        double         slope[2];
     1695        double         l1l2l3[3];
     1696        double         pe_g_gaussian[numdof];
     1697        GaussTria*     gauss=NULL;
     1698
     1699        /*Initialize Element vector and return if necessary*/
     1700        if(IsOnWater()) return NULL;
     1701        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
     1702
     1703        /*Retrieve all inputs and parameters*/
     1704        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1705        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     1706        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     1707        Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
     1708        Input* drag_input=inputs->GetInput(DragCoefficientEnum);ISSMASSERT(drag_input);
     1709
     1710        /* Start  looping on the number of gaussian points: */
     1711        gauss=new GaussTria(2);
     1712        for(ig=gauss->begin();ig<gauss->end();ig++){
     1713
     1714                gauss->GaussPoint(ig);
     1715
     1716                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     1717                GetNodalFunctions(l1l2l3, gauss);
     1718
     1719                thickness_input->GetParameterValue(&thickness,gauss);
     1720                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     1721               
     1722                /*In case we have plastic basal drag, compute plastic stress at gaussian point from k1, k2 and k3 fields in the
     1723                 * element itself: */
     1724                if(drag_type==1) drag_input->GetParameterValue(&plastic_stress,gauss);
     1725
     1726                driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG()*thickness;
     1727
     1728                /*Build pe_g_gaussian vector: */
     1729                if(drag_type==1){
     1730                        for (i=0;i<NUMVERTICES;i++){
     1731                                for (j=0;j<NDOF2;j++){
     1732                                        pe->values[i*NDOF2+j]+=(-driving_stress_baseline*slope[j]-plastic_stress)*Jdet*gauss->weight*l1l2l3[i];
     1733                                }
     1734                        }
     1735                }
     1736                else {
     1737                        for (i=0;i<NUMVERTICES;i++){
     1738                                for (j=0;j<NDOF2;j++){
     1739                                        pe->values[i*NDOF2+j]+=-driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l2l3[i];
     1740                                }
     1741                        }
     1742                }
     1743        }
     1744
     1745        /*Clean up and return*/
     1746        delete gauss;
     1747        return pe;
     1748}
     1749/*}}}*/
     1750/*FUNCTION Tria::CreatePVectorAdjointBalancedthickness{{{1*/
     1751ElementVector* Tria::CreatePVectorAdjointBalancedthickness(void){
     1752
     1753        /*Constants*/
     1754        const int    numdof=1*NUMVERTICES;
     1755
     1756        /*Intermediaries */
     1757        int         i,ig;
     1758        double      Jdet;
     1759        double      thickness,thicknessobs,weight;
     1760        double      xyz_list[NUMVERTICES][3];
     1761        double      l1l2l3[3];
     1762        GaussTria*  gauss=NULL;
     1763
     1764        /*Initialize Element vector and return if necessary*/
     1765        if(IsOnWater()) return NULL;
     1766        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1767
     1768        /*Retrieve all inputs and parameters*/
     1769        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1770        Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
     1771        Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
     1772        Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
     1773
     1774        /* Start  looping on the number of gaussian points: */
     1775        gauss=new GaussTria(2);
     1776        for(ig=gauss->begin();ig<gauss->end();ig++){
     1777
     1778                gauss->GaussPoint(ig);
     1779
     1780                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     1781                GetNodalFunctions(l1l2l3, gauss);
     1782
     1783                thickness_input->GetParameterValue(&thickness, gauss);
     1784                thicknessobs_input->GetParameterValue(&thicknessobs, gauss);
     1785                weights_input->GetParameterValue(&weight, gauss);
     1786
     1787                for(i=0;i<numdof;i++) pe->values[i]+=(thicknessobs-thickness)*weight*Jdet*gauss->weight*l1l2l3[i];
     1788        }
     1789
     1790        /*Clean up and return*/
     1791        delete gauss;
     1792        return pe;
     1793}
     1794/*}}}*/
     1795/*FUNCTION Tria::CreatePVectorAdjointHoriz{{{1*/
     1796ElementVector* Tria::CreatePVectorAdjointHoriz(void){
     1797
     1798        /*Constants*/
     1799        const int    numdof=NDOF2*NUMVERTICES;
     1800
     1801        /*Intermediaries */
     1802        int        i,ig,response;
     1803        double     Jdet;
     1804        double     obs_velocity_mag,velocity_mag;
     1805        double     dux,duy,meanvel,epsvel;
     1806        double     scalex=0,scaley=0,scale=0,S=0;
     1807        double     xyz_list[NUMVERTICES][3];
     1808        double     vx_list[NUMVERTICES];
     1809        double     vy_list[NUMVERTICES];
     1810        double     obs_vx_list[NUMVERTICES];
     1811        double     obs_vy_list[NUMVERTICES];
     1812        double     dux_list[NUMVERTICES];
     1813        double     duy_list[NUMVERTICES];
     1814        double     weights_list[NUMVERTICES];
     1815        double     l1l2l3[3];
     1816        GaussTria* gauss=NULL;
     1817
     1818        /*Initialize Element vector and return if necessary*/
     1819        if(IsOnWater()) return NULL;
     1820        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     1821
     1822        /*Retrieve all inputs and parameters*/
     1823        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     1824        this->parameters->FindParam(&meanvel,MeanVelEnum);
     1825        this->parameters->FindParam(&epsvel,EpsVelEnum);
     1826        GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
     1827        GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
     1828        GetParameterListOnVertices(&vx_list[0],VxEnum);
     1829        GetParameterListOnVertices(&vy_list[0],VyEnum);
     1830        GetParameterListOnVertices(&weights_list[0],WeightsEnum);
     1831        inputs->GetParameterValue(&response,CmResponseEnum);
     1832        if(response==SurfaceAverageVelMisfitEnum){
     1833                inputs->GetParameterValue(&S,SurfaceAreaEnum);
     1834        }
     1835
     1836        /*Get Du at the 3 nodes (integration of the linearized function)
     1837         * Here we integrate linearized functions:
     1838         *               
     1839         * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
     1840         *
     1841         *       d J                  dJ_i
     1842         * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
     1843         *       d u                  du_i
     1844         *
     1845         * where J_i are the misfits at the 3 nodes of the triangle
     1846         *       Phi_i is the nodal function (P1) with respect to
     1847         *       the vertex i
     1848         */
     1849        if(response==SurfaceAbsVelMisfitEnum){
     1850                /*We are using an absolute misfit:
     1851                 *
     1852                 *      1  [           2              2 ]
     1853                 * J = --- | (u - u   )  +  (v - v   )  |
     1854                 *      2  [       obs            obs   ]
     1855                 *
     1856                 *        dJ
     1857                 * DU = - -- = (u   - u )
     1858                 *        du     obs
     1859                 */
     1860                for (i=0;i<NUMVERTICES;i++){
     1861                        dux_list[i]=obs_vx_list[i]-vx_list[i];
     1862                        duy_list[i]=obs_vy_list[i]-vy_list[i];
     1863                }
     1864        }
     1865        else if(response==SurfaceRelVelMisfitEnum){
     1866                /*We are using a relative misfit:
     1867                 *                       
     1868                 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
     1869                 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
     1870                 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
     1871                 *              obs                        obs                     
     1872                 *
     1873                 *        dJ     \bar{v}^2
     1874                 * DU = - -- = ------------- (u   - u )
     1875                 *        du   (u   + eps)^2    obs
     1876                 *               obs
     1877                 */
     1878                for (i=0;i<NUMVERTICES;i++){
     1879                        scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
     1880                        scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
     1881                        if(obs_vx_list[i]==0)scalex=0;
     1882                        if(obs_vy_list[i]==0)scaley=0;
     1883                        dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
     1884                        duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
     1885                }
     1886        }
     1887        else if(response==SurfaceLogVelMisfitEnum){
     1888                /*We are using a logarithmic misfit:
     1889                 *                       
     1890                 *                 [        vel + eps     ] 2
     1891                 * J = 4 \bar{v}^2 | log ( -----------  ) | 
     1892                 *                 [       vel   + eps    ]
     1893                 *                            obs
     1894                 *
     1895                 *        dJ                 2 * log(...)
     1896                 * DU = - -- = - 4 \bar{v}^2 -------------  u
     1897                 *        du                 vel^2 + eps
     1898                 *           
     1899                 */
     1900                for (i=0;i<NUMVERTICES;i++){
     1901                        velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
     1902                        obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
     1903                        scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
     1904                        dux_list[i]=scale*vx_list[i];
     1905                        duy_list[i]=scale*vy_list[i];
     1906                }
     1907        }
     1908        else if(response==SurfaceAverageVelMisfitEnum){
     1909                /*We are using an spacially average absolute misfit:
     1910                 *
     1911                 *      1                    2              2
     1912                 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
     1913                 *      S                obs            obs
     1914                 *
     1915                 *        dJ      1       1
     1916                 * DU = - -- = - --- ----------- * 2 (u - u   )
     1917                 *        du      S  2 sqrt(...)           obs
     1918                 */
     1919                for (i=0;i<NUMVERTICES;i++){
     1920                        scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
     1921                        dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
     1922                        duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
     1923                }
     1924        }
     1925        else if(response==SurfaceLogVxVyMisfitEnum){
     1926                /*We are using an logarithmic 2 misfit:
     1927                 *
     1928                 *      1            [        |u| + eps     2          |v| + eps     2  ]
     1929                 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   | 
     1930                 *      2            [       |u    |+ eps              |v    |+ eps     ]
     1931                 *                              obs                       obs
     1932                 *        dJ                              1      u                             1
     1933                 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
     1934                 *        du                         |u| + eps  |u|                           u + eps
     1935                 */
     1936                for (i=0;i<NUMVERTICES;i++){
     1937                        dux_list[i] = - pow(meanvel,(double)2)*(
     1938                                                log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
     1939                        duy_list[i] = - pow(meanvel,(double)2)*(
     1940                                                log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
     1941                }
     1942        }
     1943        else{
     1944                /*Not supported yet! : */
     1945                ISSMERROR("response %s not supported yet",EnumToString(response));
     1946        }
     1947
     1948        /*Apply weights to DU*/
     1949        for (i=0;i<NUMVERTICES;i++){
     1950                dux_list[i]=weights_list[i]*dux_list[i];
     1951                duy_list[i]=weights_list[i]*duy_list[i];
     1952        }
     1953
     1954        /* Start  looping on the number of gaussian points: */
     1955        gauss=new GaussTria(2);
     1956        for(ig=gauss->begin();ig<gauss->end();ig++){
     1957
     1958                gauss->GaussPoint(ig);
     1959
     1960                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     1961                GetNodalFunctions(l1l2l3, gauss);
     1962
     1963                TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
     1964                TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
     1965
     1966                for (i=0;i<NUMVERTICES;i++){
     1967                        pe->values[i*NDOF2+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
     1968                        pe->values[i*NDOF2+1]+=duy*Jdet*gauss->weight*l1l2l3[i];
     1969                }
     1970        }
     1971
     1972        /*Clean up and return*/
     1973        delete gauss;
     1974        return pe;
     1975}
     1976/*}}}*/
     1977/*FUNCTION Tria::CreatePVectorAdjointStokes{{{1*/
     1978ElementVector* Tria::CreatePVectorAdjointStokes(void){
     1979
     1980        /*Intermediaries */
     1981        int        i,ig;
     1982        int        fit=-1;
     1983        int        response;
     1984        double     Jdet;
     1985        double     obs_velocity_mag,velocity_mag;
     1986        double     dux,duy,meanvel,epsvel;
     1987        double     scalex=0,scaley=0,scale=0,S=0;
     1988        double     xyz_list[NUMVERTICES][3];
     1989        double     vx_list[NUMVERTICES];
     1990        double     vy_list[NUMVERTICES];
     1991        double     obs_vx_list[NUMVERTICES];
     1992        double     obs_vy_list[NUMVERTICES];
     1993        double     dux_list[NUMVERTICES];
     1994        double     duy_list[NUMVERTICES];
     1995        double     weights_list[NUMVERTICES];
     1996        double     l1l2l3[3];
     1997        GaussTria* gauss=NULL;
     1998
     1999        /*Initialize Element vector and return if necessary*/
     2000        if(IsOnWater()) return NULL;
     2001        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
     2002
     2003        /*Retrieve all inputs and parameters*/
     2004        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2005        this->parameters->FindParam(&meanvel,MeanVelEnum);
     2006        this->parameters->FindParam(&epsvel,EpsVelEnum);
     2007        GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
     2008        GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
     2009        GetParameterListOnVertices(&vx_list[0],VxEnum);
     2010        GetParameterListOnVertices(&vy_list[0],VyEnum);
     2011        GetParameterListOnVertices(&weights_list[0],WeightsEnum);
     2012        inputs->GetParameterValue(&response,CmResponseEnum);
     2013        if(response==SurfaceAverageVelMisfitEnum){
     2014                inputs->GetParameterValue(&S,SurfaceAreaEnum);
     2015        }
     2016
     2017        /*Get Du at the 3 nodes (integration of the linearized function)
     2018         * Here we integrate linearized functions:
     2019         *               
     2020         * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
     2021         *
     2022         *       d J                  dJ_i
     2023         * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
     2024         *       d u                  du_i
     2025         *
     2026         * where J_i are the misfits at the 3 nodes of the triangle
     2027         *       Phi_i is the nodal function (P1) with respect to
     2028         *       the vertex i
     2029         */
     2030        if(response==SurfaceAbsVelMisfitEnum){
     2031                /*We are using an absolute misfit:
     2032                 *
     2033                 *      1  [           2              2 ]
     2034                 * J = --- | (u - u   )  +  (v - v   )  |
     2035                 *      2  [       obs            obs   ]
     2036                 *
     2037                 *        dJ             2
     2038                 * DU = - -- = (u   - u )
     2039                 *        du     obs
     2040                 */
     2041                for (i=0;i<NUMVERTICES;i++){
     2042                        dux_list[i]=obs_vx_list[i]-vx_list[i];
     2043                        duy_list[i]=obs_vy_list[i]-vy_list[i];
     2044                }
     2045        }
     2046        else if(response==SurfaceRelVelMisfitEnum){
     2047                /*We are using a relative misfit:
     2048                 *                       
     2049                 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
     2050                 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
     2051                 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
     2052                 *              obs                        obs                     
     2053                 *
     2054                 *        dJ     \bar{v}^2
     2055                 * DU = - -- = ------------- (u   - u )
     2056                 *        du   (u   + eps)^2    obs
     2057                 *               obs
     2058                 */
     2059                for (i=0;i<NUMVERTICES;i++){
     2060                        scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
     2061                        scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
     2062                        if(obs_vx_list[i]==0)scalex=0;
     2063                        if(obs_vy_list[i]==0)scaley=0;
     2064                        dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
     2065                        duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
     2066                }
     2067        }
     2068        else if(response==SurfaceLogVelMisfitEnum){
     2069                /*We are using a logarithmic misfit:
     2070                 *                       
     2071                 *                 [        vel + eps     ] 2
     2072                 * J = 4 \bar{v}^2 | log ( -----------  ) | 
     2073                 *                 [       vel   + eps    ]
     2074                 *                            obs
     2075                 *
     2076                 *        dJ                 2 * log(...)
     2077                 * DU = - -- = - 4 \bar{v}^2 -------------  u
     2078                 *        du                 vel^2 + eps
     2079                 *           
     2080                 */
     2081                for (i=0;i<NUMVERTICES;i++){
     2082                        velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
     2083                        obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
     2084                        scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
     2085                        dux_list[i]=scale*vx_list[i];
     2086                        duy_list[i]=scale*vy_list[i];
     2087                }
     2088        }
     2089        else if(response==SurfaceAverageVelMisfitEnum){
     2090                /*We are using an spacially average absolute misfit:
     2091                 *
     2092                 *      1                    2              2
     2093                 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
     2094                 *      S                obs            obs
     2095                 *
     2096                 *        dJ      1       1
     2097                 * DU = - -- = - --- ----------- * 2 (u - u   )
     2098                 *        du      S  2 sqrt(...)           obs
     2099                 */
     2100                for (i=0;i<NUMVERTICES;i++){
     2101                        scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
     2102                        dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
     2103                        duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
     2104                }
     2105        }
     2106        else if(response==SurfaceLogVxVyMisfitEnum){
     2107                /*We are using an logarithmic 2 misfit:
     2108                 *
     2109                 *      1            [        |u| + eps     2          |v| + eps     2  ]
     2110                 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   | 
     2111                 *      2            [       |u    |+ eps              |v    |+ eps     ]
     2112                 *                              obs                       obs
     2113                 *        dJ                              1      u                             1
     2114                 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
     2115                 *        du                         |u| + eps  |u|                           u + eps
     2116                 */
     2117                for (i=0;i<NUMVERTICES;i++){
     2118                        dux_list[i] = - pow(meanvel,(double)2)*(
     2119                                                log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
     2120                        duy_list[i] = - pow(meanvel,(double)2)*(
     2121                                                log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
     2122                }
     2123        }
     2124        else{
     2125                /*Not supported yet! : */
     2126                ISSMERROR("response %s not supported yet",EnumToString(response));
     2127        }
     2128
     2129        /*Apply weights to DU*/
     2130        for (i=0;i<NUMVERTICES;i++){
     2131                dux_list[i]=weights_list[i]*dux_list[i];
     2132                duy_list[i]=weights_list[i]*duy_list[i];
     2133        }
     2134
     2135        /* Start  looping on the number of gaussian points: */
     2136        gauss=new GaussTria(2);
     2137        for(ig=gauss->begin();ig<gauss->end();ig++){
     2138
     2139                gauss->GaussPoint(ig);
     2140
     2141                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     2142                GetNodalFunctions(l1l2l3, gauss);
     2143
     2144                TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
     2145                TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
     2146
     2147                for (i=0;i<NUMVERTICES;i++){
     2148                        pe->values[i*NDOF4+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
     2149                        pe->values[i*NDOF4+1]+=duy*Jdet*gauss->weight*l1l2l3[i];
     2150                }
     2151        }
     2152
     2153        /*Clean up and return*/
     2154        delete gauss;
     2155        return pe;
     2156}
     2157/*}}}*/
     2158/*FUNCTION Tria::CreatePVectorDiagnosticHutter{{{1*/
     2159ElementVector* Tria::CreatePVectorDiagnosticHutter(void){
     2160
     2161        /*Intermediaries */
     2162        int        i,connectivity;
     2163        double     constant_part,ub,vb;
     2164        double     rho_ice,gravity,n,B;
     2165        double     slope2,thickness;
     2166        double     slope[2];
     2167        GaussTria* gauss=NULL;
     2168
     2169        /*Initialize Element vector and return if necessary*/
     2170        if(IsOnWater()) return NULL;
     2171        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2172
     2173        /*Retrieve all inputs and parameters*/
     2174        rho_ice=matpar->GetRhoIce();
     2175        gravity=matpar->GetG();
     2176        n=matice->GetN();
     2177        B=matice->GetBbar();
     2178        Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
     2179        Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
     2180        Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
     2181
     2182        /*Spawn 3 sing elements: */
     2183        gauss=new GaussTria();
     2184        for(i=0;i<NUMVERTICES;i++){
     2185
     2186                gauss->GaussVertex(i);
     2187
     2188                connectivity=nodes[i]->GetConnectivity();
     2189
     2190                thickness_input->GetParameterValue(&thickness,gauss);
     2191                slopex_input->GetParameterValue(&slope[0],gauss);
     2192                slopey_input->GetParameterValue(&slope[1],gauss);
     2193                slope2=pow(slope[0],2)+pow(slope[1],2);
     2194
     2195                constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
     2196
     2197                ub=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[0];
     2198                vb=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[1];
     2199
     2200                pe->values[2*i]  =(ub-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[0])/(double)connectivity;
     2201                pe->values[2*i+1]=(vb-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[1])/(double)connectivity;
     2202        }
     2203
     2204        /*Clean up and return*/
     2205        delete gauss;
     2206        return pe;
     2207}
     2208/*}}}*/
     2209/*FUNCTION Tria::CreatePVectorPrognostic{{{1*/
     2210ElementVector* Tria::CreatePVectorPrognostic(void){
     2211
     2212        switch(GetElementType()){
     2213                case P1Enum:
     2214                        return CreatePVectorPrognostic_CG();
     2215                case P1DGEnum:
     2216                        return CreatePVectorPrognostic_DG();
     2217                default:
     2218                        ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
     2219        }
     2220}
     2221/*}}}*/
     2222/*FUNCTION Tria::CreatePVectorPrognostic_CG {{{1*/
     2223ElementVector* Tria::CreatePVectorPrognostic_CG(void){
     2224
     2225        /*Constants*/
     2226        const int    numdof=NDOF1*NUMVERTICES;
     2227
     2228        /*Intermediaries */
     2229        int        i,j,ig;
     2230        double     Jdettria,dt;
     2231        double     accumulation_g,melting_g,thickness_g;
     2232        double     xyz_list[NUMVERTICES][3];
     2233        double     L[NUMVERTICES];
     2234        GaussTria* gauss=NULL;
     2235
     2236        /*Initialize Element vector and return if necessary*/
     2237        if(IsOnWater()) return NULL;
     2238        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2239
     2240        /*Retrieve all inputs and parameters*/
     2241        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2242        this->parameters->FindParam(&dt,DtEnum);
     2243        Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
     2244        Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
     2245        Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
     2246
     2247        /* Start  looping on the number of gaussian points: */
     2248        gauss=new GaussTria(2);
     2249        for(ig=gauss->begin();ig<gauss->end();ig++){
     2250
     2251                gauss->GaussPoint(ig);
     2252
     2253                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     2254                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     2255
     2256                accumulation_input->GetParameterValue(&accumulation_g,gauss);
     2257                melting_input->GetParameterValue(&melting_g,gauss);
     2258                thickness_input->GetParameterValue(&thickness_g,gauss);
     2259
     2260                for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
     2261        }
     2262
     2263        /*Clean up and return*/
     2264        delete gauss;
     2265        return pe;
     2266}
     2267/*}}}*/
     2268/*FUNCTION Tria::CreatePVectorPrognostic_DG {{{1*/
     2269ElementVector* Tria::CreatePVectorPrognostic_DG(void){
     2270
     2271        /*Constants*/
     2272        const int    numdof=NDOF1*NUMVERTICES;
     2273
     2274        /*Intermediaries */
     2275        int        i,j,ig;
     2276        double     Jdettria,dt;
     2277        double     accumulation_g,melting_g,thickness_g;
     2278        double     xyz_list[NUMVERTICES][3];
     2279        double     L[NUMVERTICES];
     2280        GaussTria* gauss=NULL;
     2281
     2282        /*Initialize Element vector and return if necessary*/
     2283        if(IsOnWater()) return NULL;
     2284        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2285
     2286        /*Retrieve all inputs and parameters*/
     2287        this->parameters->FindParam(&dt,DtEnum);
     2288        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2289        Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
     2290        Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
     2291        Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
     2292
     2293        /* Start  looping on the number of gaussian points: */
     2294        gauss=new GaussTria(2);
     2295        for(ig=gauss->begin();ig<gauss->end();ig++){
     2296
     2297                gauss->GaussPoint(ig);
     2298
     2299                GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
     2300                GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
     2301
     2302                accumulation_input->GetParameterValue(&accumulation_g,gauss);
     2303                melting_input->GetParameterValue(&melting_g,gauss);
     2304                thickness_input->GetParameterValue(&thickness_g,gauss);
     2305
     2306                for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
     2307        }
     2308
     2309        /*Clean up and return*/
     2310        delete gauss;
     2311        return pe;
     2312}
     2313/*}}}*/
     2314/*FUNCTION Tria::CreatePVectorSlope {{{1*/
     2315ElementVector* Tria::CreatePVectorSlope(void){
     2316
     2317        /*Constants*/
     2318        const int    numdof=NDOF1*NUMVERTICES;
     2319       
     2320        /*Intermediaries */
     2321        int        i,j,ig;
     2322        int        analysis_type;
     2323        double     Jdet;
     2324        double     xyz_list[NUMVERTICES][3];
     2325        double     slope[2];
     2326        double     l1l2l3[3];
     2327        GaussTria* gauss=NULL;
     2328
     2329        /*Initialize Element vector and return if necessary*/
     2330        if(IsOnWater()) return NULL;
     2331        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2332
     2333        /*Retrieve all inputs and parameters*/
     2334        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     2335        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2336        Input* slope_input=NULL;
     2337        if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==SurfaceSlopeYAnalysisEnum)){
     2338                slope_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(slope_input);
     2339        }
     2340        if ( (analysis_type==BedSlopeXAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
     2341                slope_input=inputs->GetInput(BedEnum);     ISSMASSERT(slope_input);
     2342        }
     2343               
     2344        /* Start  looping on the number of gaussian points: */
     2345        gauss=new GaussTria(2);
     2346        for(ig=gauss->begin();ig<gauss->end();ig++){
     2347
     2348                gauss->GaussPoint(ig);
     2349
     2350                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     2351                GetNodalFunctions(l1l2l3, gauss);
     2352
     2353                slope_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
     2354
     2355                if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==BedSlopeXAnalysisEnum)){
     2356                        for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[0]*l1l2l3[i];
     2357                }
     2358                if ( (analysis_type==SurfaceSlopeYAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
     2359                        for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[1]*l1l2l3[i];
     2360                }
     2361        }
     2362
     2363        /*Clean up and return*/
     2364        delete gauss;
     2365        return pe;
     2366}
     2367/*}}}*/
     2368/*FUNCTION Tria::CreatePVectorThermalShelf {{{1*/
     2369ElementVector* Tria::CreatePVectorThermalShelf(void){
     2370       
     2371        /*Constants*/
     2372        const int  numdof=NUMVERTICES*NDOF1;
     2373
     2374        /*Intermediaries */
     2375        int        i,ig;
     2376        double     Jdet;
     2377        double     mixed_layer_capacity,thermal_exchange_velocity;
     2378        double     rho_ice,rho_water,pressure,dt,scalar_ocean;
     2379        double     meltingpoint,beta,heatcapacity,t_pmp;
     2380        double     xyz_list[NUMVERTICES][3];
     2381        double     l1l2l3[NUMVERTICES];
     2382        GaussTria* gauss=NULL;
     2383
     2384        /*Initialize Element vector and return if necessary*/
     2385        if(IsOnWater()) return NULL;
     2386        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2387
     2388        /*Retrieve all inputs and parameters*/
     2389        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2390        mixed_layer_capacity=matpar->GetMixedLayerCapacity();
     2391        thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
     2392        rho_water=matpar->GetRhoWater();
     2393        rho_ice=matpar->GetRhoIce();
     2394        heatcapacity=matpar->GetHeatCapacity();
     2395        beta=matpar->GetBeta();
     2396        meltingpoint=matpar->GetMeltingPoint();
     2397        this->parameters->FindParam(&dt,DtEnum);
     2398        Input* pressure_input=inputs->GetInput(PressureEnum); ISSMASSERT(pressure_input);
     2399
     2400        /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     2401        gauss=new GaussTria(2);
     2402        for(ig=gauss->begin();ig<gauss->end();ig++){
     2403
     2404                gauss->GaussPoint(ig);
     2405
     2406                GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
     2407                GetNodalFunctions(&l1l2l3[0], gauss);
     2408
     2409                pressure_input->GetParameterValue(&pressure,gauss);
     2410                t_pmp=meltingpoint-beta*pressure;
     2411
     2412                scalar_ocean=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(t_pmp)/(heatcapacity*rho_ice);
     2413                if(dt) scalar_ocean=dt*scalar_ocean;
     2414
     2415                for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*l1l2l3[i];
     2416        }
     2417
     2418        /*Clean up and return*/
     2419        delete gauss;
     2420        return pe;
     2421}
     2422/*}}}*/
     2423/*FUNCTION Tria::CreatePVectorThermalSheet {{{1*/
     2424ElementVector* Tria::CreatePVectorThermalSheet(void){
     2425
     2426        /*Constants*/
     2427        const int  numdof=NUMVERTICES*NDOF1;
     2428
     2429        /*Intermediaries */
     2430        int        i,ig;
     2431        int        analysis_type,drag_type;
     2432        double     xyz_list[NUMVERTICES][3];
     2433        double     Jdet,dt;
     2434        double     rho_ice,heatcapacity,geothermalflux_value;
     2435        double     basalfriction,alpha2,vx,vy,pressure;
     2436        double     pressure_list[3];
     2437        double     scalar;
     2438        double     l1l2l3[NUMVERTICES];
     2439        Friction*  friction=NULL;
     2440        GaussTria* gauss=NULL;
     2441
     2442        /*Initialize Element vector and return if necessary*/
     2443        if(IsOnWater()) return NULL;
     2444        ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
     2445
     2446        /*Retrieve all inputs and parameters*/
     2447        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2448        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     2449        rho_ice=matpar->GetRhoIce();
     2450        heatcapacity=matpar->GetHeatCapacity();
     2451        this->inputs->GetParameterValue(&dt,DtEnum);
     2452        Input* vx_input=inputs->GetInput(VxEnum);                         ISSMASSERT(vx_input);
     2453        Input* vy_input=inputs->GetInput(VyEnum);                         ISSMASSERT(vy_input);
     2454        Input* vz_input=inputs->GetInput(VzEnum);                         ISSMASSERT(vz_input);
     2455        Input* geothermalflux_input=inputs->GetInput(GeothermalFluxEnum); ISSMASSERT(geothermalflux_input);
     2456
     2457        /*Build frictoin element, needed later: */
     2458        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     2459        if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
     2460        friction=new Friction("3d",inputs,matpar,analysis_type);
     2461
     2462        /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     2463        gauss=new GaussTria(2);
     2464        for(ig=gauss->begin();ig<gauss->end();ig++){
     2465
     2466                gauss->GaussPoint(ig);
     2467
     2468                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
     2469                GetNodalFunctions(&l1l2l3[0], gauss);
     2470
     2471                geothermalflux_input->GetParameterValue(&geothermalflux_value,gauss);
     2472                friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
     2473                vx_input->GetParameterValue(&vx,gauss);
     2474                vy_input->GetParameterValue(&vy,gauss);
     2475                basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
     2476               
     2477                scalar=gauss->weight*Jdet*(basalfriction+geothermalflux_value)/(heatcapacity*rho_ice);
     2478                if(dt) scalar=dt*scalar;
     2479
     2480                for(i=0;i<numdof;i++) pe->values[i]+=scalar*l1l2l3[i];
     2481        }
     2482
     2483        /*Clean up and return*/
     2484        delete gauss;
     2485        delete friction;
     2486        return pe;
     2487}
     2488/*}}}*/
     2489/*FUNCTION Tria::ComputeBasalStress {{{1*/
     2490void  Tria::ComputeBasalStress(Vec eps){
     2491        ISSMERROR("Not Implemented yet");
     2492}
     2493/*}}}*/
     2494/*FUNCTION Tria::ComputeStrainRate {{{1*/
     2495void  Tria::ComputeStrainRate(Vec eps){
     2496        ISSMERROR("Not Implemented yet");
     2497}
     2498/*}}}*/
     2499/*FUNCTION Tria::Configure {{{1*/
     2500void  Tria::Configure(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
     2501       
     2502        /*go into parameters and get the analysis_counter: */
     2503        int analysis_counter;
     2504        parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
     2505
     2506        /*Get Element type*/
     2507        this->element_type=this->element_type_list[analysis_counter];
     2508
     2509        /*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective
     2510         * datasets, using internal ids and offsets hidden in hooks: */
     2511        if(this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
     2512        this->hmatice->configure(materialsin);
     2513        this->hmatpar->configure(materialsin);
     2514
     2515        /*Now, go pick up the objects inside the hooks: */
     2516        if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
     2517        else this->nodes=NULL;
     2518        this->matice=(Matice*)this->hmatice->delivers();
     2519        this->matpar=(Matpar*)this->hmatpar->delivers();
     2520
     2521        /*point parameters to real dataset: */
     2522        this->parameters=parametersin;
     2523
     2524}
     2525/*}}}*/
     2526/*FUNCTION Tria::ControlInputGetGradient{{{1*/
     2527void Tria::ControlInputGetGradient(Vec gradient,int enum_type){
     2528
     2529        int doflist1[NUMVERTICES];
     2530        Input* input=NULL;
     2531
     2532        if(enum_type==RheologyBbarEnum){
     2533                input=(Input*)matice->inputs->GetInput(enum_type);
     2534        }
     2535        else{
     2536                input=inputs->GetInput(enum_type);
     2537        }
     2538        if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
     2539        if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
     2540
     2541        this->GetDofList1(&doflist1[0]);
     2542        ((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
     2543
     2544}/*}}}*/
     2545/*FUNCTION Tria::ControlInputScaleGradient{{{1*/
     2546void Tria::ControlInputScaleGradient(int enum_type,double scale){
     2547
     2548        Input* input=NULL;
     2549
     2550        if(enum_type==RheologyBbarEnum){
     2551                input=(Input*)matice->inputs->GetInput(enum_type);
     2552        }
     2553        else{
     2554                input=inputs->GetInput(enum_type);
     2555        }
     2556        if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
     2557        if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
     2558
     2559        ((ControlInput*)input)->ScaleGradient(scale);
     2560}/*}}}*/
     2561/*FUNCTION Tria::ControlInputSetGradient{{{1*/
     2562void Tria::ControlInputSetGradient(double* gradient,int enum_type){
     2563
     2564        int    doflist1[NUMVERTICES];
     2565        double grad_list[NUMVERTICES];
     2566        Input* grad_input=NULL;
     2567        Input* input=NULL;
     2568
     2569        if(enum_type==RheologyBbarEnum){
     2570                input=(Input*)matice->inputs->GetInput(enum_type);
     2571        }
     2572        else{
     2573                input=inputs->GetInput(enum_type);
     2574        }
     2575        if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
     2576        if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
     2577
     2578        this->GetDofList1(&doflist1[0]);
     2579        for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[i]];
     2580        grad_input=new TriaVertexInput(GradientEnum,grad_list);
     2581
     2582        ((ControlInput*)input)->SetGradient(grad_input);
     2583
     2584}/*}}}*/
     2585/*FUNCTION Tria::DeepEcho{{{1*/
     2586void Tria::DeepEcho(void){
     2587
     2588        printf("Tria:\n");
     2589        printf("   id: %i\n",id);
     2590        if(nodes){
     2591                nodes[0]->DeepEcho();
     2592                nodes[1]->DeepEcho();
     2593                nodes[2]->DeepEcho();
     2594        }
     2595        else printf("nodes = NULL\n");
     2596
     2597        if (matice) matice->DeepEcho();
     2598        else printf("matice = NULL\n");
     2599
     2600        if (matpar) matpar->DeepEcho();
     2601        else printf("matpar = NULL\n");
     2602
     2603        printf("   parameters\n");
     2604        if (parameters) parameters->DeepEcho();
     2605        else printf("parameters = NULL\n");
     2606
     2607        printf("   inputs\n");
     2608        if (inputs) inputs->DeepEcho();
     2609        else printf("inputs=NULL\n");
     2610
     2611        if (results) results->DeepEcho();
     2612        else printf("results=NULL\n");
     2613       
     2614        return;
     2615}
     2616/*}}}*/
     2617/*FUNCTION Tria::DeleteResults {{{1*/
     2618void  Tria::DeleteResults(void){
     2619
     2620        /*Delete and reinitialize results*/
     2621        delete this->results;
     2622        this->results=new Results();
     2623
     2624}
     2625/*}}}*/
     2626/*FUNCTION Tria::Echo{{{1*/
     2627void Tria::Echo(void){
     2628        printf("Tria:\n");
     2629        printf("   id: %i\n",id);
     2630        if(nodes){
     2631                nodes[0]->Echo();
     2632                nodes[1]->Echo();
     2633                nodes[2]->Echo();
     2634        }
     2635        else printf("nodes = NULL\n");
     2636
     2637        if (matice) matice->Echo();
     2638        else printf("matice = NULL\n");
     2639
     2640        if (matpar) matpar->Echo();
     2641        else printf("matpar = NULL\n");
     2642
     2643        printf("   parameters\n");
     2644        if (parameters) parameters->Echo();
     2645        else printf("parameters = NULL\n");
     2646
     2647        printf("   inputs\n");
     2648        if (inputs) inputs->Echo();
     2649        else printf("inputs=NULL\n");
     2650
     2651        if (results) results->Echo();
     2652        else printf("results=NULL\n");
     2653}
     2654/*}}}*/
     2655/*FUNCTION Tria::Enum {{{1*/
     2656int Tria::Enum(void){
     2657
     2658        return TriaEnum;
     2659
     2660}
     2661/*}}}*/
     2662/*FUNCTION Tria::GetArea {{{1*/
     2663double Tria::GetArea(void){
     2664
     2665        double area=0;
     2666        double xyz_list[NUMVERTICES][3];
     2667        double x1,y1,x2,y2,x3,y3;
     2668
     2669        /*Get xyz list: */
     2670        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2671        x1=xyz_list[0][0]; y1=xyz_list[0][1];
     2672        x2=xyz_list[1][0]; y2=xyz_list[1][1];
     2673        x3=xyz_list[2][0]; y3=xyz_list[2][1];
     2674 
     2675        return (x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
     2676}
     2677/*}}}*/
     2678/*FUNCTION Tria::GetDofList {{{1*/
     2679void  Tria::GetDofList(int** pdoflist, int approximation_enum,int setenum){
     2680
     2681        int i,j;
     2682        int count=0;
     2683        int numberofdofs=0;
     2684        int* doflist=NULL;
     2685
     2686        /*First, figure out size of doflist and create it: */
     2687        for(i=0;i<3;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
     2688        doflist=(int*)xmalloc(numberofdofs*sizeof(int));
     2689
     2690        /*Populate: */
     2691        count=0;
     2692        for(i=0;i<3;i++){
     2693                nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
     2694                count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
     2695        }
     2696
     2697        /*Assign output pointers:*/
     2698        *pdoflist=doflist;
     2699}
     2700/*}}}*/
     2701/*FUNCTION Tria::GetDofList1 {{{1*/
     2702void  Tria::GetDofList1(int* doflist){
     2703
     2704        int i;
     2705        for(i=0;i<3;i++) doflist[i]=nodes[i]->GetDofList1();
     2706
     2707}
     2708/*}}}*/
     2709/*FUNCTION Tria::GetElementType {{{1*/
     2710int Tria::GetElementType(){
     2711
     2712        /*return TriaRef field*/
     2713        return this->element_type;
     2714
     2715}
     2716/*}}}*/
     2717/*FUNCTION Tria::GetNodeIndex {{{1*/
     2718int Tria::GetNodeIndex(Node* node){
     2719
     2720        ISSMASSERT(nodes);
     2721        for(int i=0;i<NUMVERTICES;i++){
     2722                if(node==nodes[i])
     2723                 return i;
     2724        }
     2725        ISSMERROR("Node provided not found among element nodes");
     2726}
     2727/*}}}*/
     2728/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
     2729void Tria::GetParameterListOnVertices(double* pvalue,int enumtype){
     2730
     2731        /*Intermediaries*/
     2732        double     value[NUMVERTICES];
     2733        GaussTria *gauss              = NULL;
     2734
     2735        /*Recover input*/
     2736        Input* input=inputs->GetInput(enumtype);
     2737        if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
     2738
     2739        /*Checks in debugging mode*/
     2740        ISSMASSERT(pvalue);
     2741
     2742        /* Start looping on the number of vertices: */
     2743        gauss=new GaussTria();
     2744        for (int iv=0;iv<NUMVERTICES;iv++){
     2745                gauss->GaussVertex(iv);
     2746                input->GetParameterValue(&pvalue[iv],gauss);
     2747        }
     2748
     2749        /*clean-up*/
     2750        delete gauss;
     2751}
     2752/*}}}*/
     2753/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
     2754void Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
     2755
     2756        double     value[NUMVERTICES];
     2757        GaussTria *gauss = NULL;
     2758        Input     *input = inputs->GetInput(enumtype);
     2759
     2760        /*Checks in debugging mode*/
     2761        ISSMASSERT(pvalue);
     2762
     2763        /* Start looping on the number of vertices: */
     2764        if (input){
     2765                gauss=new GaussTria();
     2766                for (int iv=0;iv<NUMVERTICES;iv++){
     2767                        gauss->GaussVertex(iv);
     2768                        input->GetParameterValue(&pvalue[iv],gauss);
     2769                }
     2770        }
     2771        else{
     2772                for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
     2773        }
     2774
     2775        /*clean-up*/
     2776        delete gauss;
     2777}
     2778/*}}}*/
     2779/*FUNCTION Tria::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
     2780void Tria::GetParameterValue(double* pvalue,Node* node,int enumtype){
     2781
     2782        Input* input=inputs->GetInput(enumtype);
     2783        if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
     2784
     2785        GaussTria* gauss=new GaussTria();
     2786        gauss->GaussVertex(this->GetNodeIndex(node));
     2787
     2788        input->GetParameterValue(pvalue,gauss);
     2789        delete gauss;
     2790}
     2791/*}}}*/
     2792/*FUNCTION Tria::GetSidList {{{1*/
     2793void  Tria::GetSidList(int* sidlist){
     2794
     2795        int i;
     2796        for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
     2797
     2798}
     2799/*}}}*/
     2800/*FUNCTION Tria::GetSolutionFromInputs{{{1*/
     2801void  Tria::GetSolutionFromInputs(Vec solution){
     2802
     2803        /*retrive parameters: */
     2804        int analysis_type;
     2805        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     2806
     2807        /*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
     2808        if (analysis_type==DiagnosticHorizAnalysisEnum)
     2809         GetSolutionFromInputsDiagnosticHoriz(solution);
     2810        else if (analysis_type==DiagnosticHutterAnalysisEnum)
     2811         GetSolutionFromInputsDiagnosticHutter(solution);
     2812        else
     2813         ISSMERROR("analysis: %s not supported yet",EnumToString(analysis_type));
     2814
     2815}
     2816/*}}}*/
     2817/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHoriz{{{1*/
     2818void  Tria::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
     2819
     2820        const int    numdof=NDOF2*NUMVERTICES;
     2821
     2822        int          i;
     2823        int*         doflist=NULL;
     2824        double       vx,vy;
     2825        double       values[numdof];
     2826        GaussTria*   gauss=NULL;
     2827
     2828        /*Get dof list: */
     2829        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     2830
     2831        /*Get inputs*/
     2832        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2833        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2834
     2835        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     2836        /*P1 element only for now*/
     2837        gauss=new GaussTria();
     2838        for(i=0;i<NUMVERTICES;i++){
     2839
     2840                gauss->GaussVertex(i);
     2841
     2842                /*Recover vx and vy*/
     2843                vx_input->GetParameterValue(&vx,gauss);
     2844                vy_input->GetParameterValue(&vy,gauss);
     2845                values[i*NDOF2+0]=vx;
     2846                values[i*NDOF2+1]=vy;
     2847        }
     2848
     2849        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2850
     2851        /*Free ressources:*/
     2852        delete gauss;
     2853        xfree((void**)&doflist);
     2854}
     2855/*}}}*/
     2856/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHutter{{{1*/
     2857void  Tria::GetSolutionFromInputsDiagnosticHutter(Vec solution){
     2858
     2859        const int    numdof=NDOF2*NUMVERTICES;
     2860
     2861        int i,dummy;
     2862        int*         doflist=NULL;
     2863        double       vx,vy;
     2864        double       values[numdof];
     2865        GaussTria*   gauss=NULL;
     2866
     2867        /*Get dof list: */
     2868        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     2869
     2870        /*Get inputs*/
     2871        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     2872        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     2873
     2874        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     2875        /*P1 element only for now*/
     2876        gauss=new GaussTria();
     2877        for(i=0;i<NUMVERTICES;i++){
     2878
     2879                gauss->GaussVertex(i);
     2880
     2881                /*Recover vx and vy*/
     2882                vx_input->GetParameterValue(&vx,gauss);
     2883                vy_input->GetParameterValue(&vy,gauss);
     2884                values[i*NDOF2+0]=vx;
     2885                values[i*NDOF2+1]=vy;
     2886        }
     2887
     2888        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     2889
     2890        /*Free ressources:*/
     2891        delete gauss;
     2892        xfree((void**)&doflist);
     2893}
     2894/*}}}*/
     2895/*FUNCTION Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){{{1*/
     2896void Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){
     2897        /*Compute the 2d Strain Rate (3 components):
     2898         * epsilon=[exx eyy exy] */
     2899
     2900        int i;
     2901        double epsilonvx[3];
     2902        double epsilonvy[3];
     2903
     2904        /*Check that both inputs have been found*/
     2905        if (!vx_input || !vy_input){
     2906                ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
     2907        }
     2908
     2909        /*Get strain rate assuming that epsilon has been allocated*/
     2910        vx_input->GetVxStrainRate2d(epsilonvx,xyz_list,gauss);
     2911        vy_input->GetVyStrainRate2d(epsilonvy,xyz_list,gauss);
     2912
     2913        /*Sum all contributions*/
     2914        for(i=0;i<3;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
     2915}
     2916/*}}}*/
     2917/*FUNCTION Tria::GetVectorFromInputs{{{1*/
     2918void  Tria::GetVectorFromInputs(Vec vector,int NameEnum){
     2919
     2920        int doflist1[NUMVERTICES];
     2921
     2922        /*Find NameEnum input in the inputs dataset, and get it to fill in the vector: */
     2923        for(int i=0;i<this->inputs->Size();i++){
     2924                Input* input=(Input*)this->inputs->GetObjectByOffset(i);
     2925                if(input->EnumType()==NameEnum){
     2926                        /*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
     2927                        this->GetDofList1(&doflist1[0]);
     2928                        input->GetVectorFromInputs(vector,&doflist1[0]);
     2929                        break;
     2930                }
     2931        }
     2932}
     2933/*}}}*/
     2934/*FUNCTION Tria::Gradj {{{1*/
     2935void  Tria::Gradj(Vec gradient,int control_type){
     2936
     2937        /*If on water, grad = 0: */
     2938        if(IsOnWater())return;
     2939
     2940        switch(control_type){
     2941                case DragCoefficientEnum:
     2942                        GradjDrag(gradient);
     2943                        break;
     2944                case RheologyBbarEnum:
     2945                        GradjB(gradient);
     2946                        break;
     2947                case DhDtEnum:
     2948                        GradjDhDt(gradient);
     2949                        break;
     2950                case VxEnum:
     2951                        GradjVx(gradient);
     2952                        break;
     2953                case VyEnum:
     2954                        GradjVy(gradient);
     2955                        break;
     2956                default:
     2957                        ISSMERROR("%s%i","control type not supported yet: ",control_type);
     2958        }
     2959}
     2960/*}}}*/
     2961/*FUNCTION Tria::GradjB{{{1*/
     2962void  Tria::GradjB(Vec gradient){
     2963
     2964        /*Intermediaries*/
     2965        int        i,ig;
     2966        int        doflist[NUMVERTICES];
     2967        double     vx,vy,lambda,mu,thickness,Jdet;
     2968        double     cm_noisedmp,viscosity_complement;
     2969        double     dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dB[NDOF2];
     2970        double     xyz_list[NUMVERTICES][3];
     2971        double     basis[3],epsilon[3];
     2972        double     dbasis[NDOF2][NUMVERTICES];
     2973        double     grad_g[NUMVERTICES];
     2974        double     grad[NUMVERTICES]={0.0};
     2975        GaussTria *gauss = NULL;
     2976
     2977        /*retrieve some parameters: */
     2978        this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
     2979
     2980        /* Get node coordinates and dof list: */
     2981        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     2982        GetDofList1(&doflist[0]);
     2983
     2984        /*Retrieve all inputs*/
     2985        Input* thickness_input=inputs->GetInput(ThicknessEnum);            ISSMASSERT(thickness_input);
     2986        Input* vx_input=inputs->GetInput(VxEnum);                          ISSMASSERT(vx_input);
     2987        Input* vy_input=inputs->GetInput(VyEnum);                          ISSMASSERT(vy_input);
     2988        Input* adjointx_input=inputs->GetInput(AdjointxEnum);              ISSMASSERT(adjointx_input);
     2989        Input* adjointy_input=inputs->GetInput(AdjointyEnum);              ISSMASSERT(adjointy_input);
     2990        Input* rheologyb_input=matice->inputs->GetInput(RheologyBbarEnum); ISSMASSERT(rheologyb_input);
     2991
     2992        /* Start  looping on the number of gaussian points: */
     2993        gauss=new GaussTria(4);
     2994        for (ig=gauss->begin();ig<gauss->end();ig++){
     2995
     2996                gauss->GaussPoint(ig);
     2997
     2998                thickness_input->GetParameterValue(&thickness,gauss);
     2999                rheologyb_input->GetParameterDerivativeValue(&dB[0],&xyz_list[0][0],gauss);
     3000                vx_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
     3001                vy_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
     3002                adjointx_input->GetParameterDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
     3003                adjointy_input->GetParameterDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
     3004
     3005                this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
     3006                matice->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
     3007
     3008                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     3009                GetNodalFunctions(basis,gauss);
     3010                GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
     3011
     3012                /*standard gradient dJ/dki*/
     3013                for (i=0;i<NUMVERTICES;i++){
     3014                        grad_g[i]=-viscosity_complement*thickness*( (2*dvx[0]+dvy[1])*2*dadjx[0]+(dvx[1]+dvy[0])*(dadjx[1]+dadjy[0])+(2*dvy[1]+dvx[0])*2*dadjy[1])*Jdet*gauss->weight*basis[i];
     3015                }
     3016                /*Add regularization term*/
     3017                for (i=0;i<NUMVERTICES;i++) grad_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dB[0]+dbasis[1][i]*dB[1]);
     3018                for(i=0;i<NUMVERTICES;i++) grad[i]+=grad_g[i];
     3019        }
     3020
     3021        VecSetValues(gradient,NUMVERTICES,doflist,(const double*)grad,ADD_VALUES);
     3022
     3023        /*clean-up*/
     3024        delete gauss;
     3025}
     3026/*}}}*/
     3027/*FUNCTION Tria::GradjDrag {{{1*/
     3028void  Tria::GradjDrag(Vec gradient){
     3029
     3030        int        i,ig;
     3031        int        drag_type,analysis_type;
     3032        int        doflist1[NUMVERTICES];
     3033        double     vx,vy,lambda,mu,alpha_complement,Jdet;
     3034        double     bed,thickness,Neff,drag,cm_noisedmp;
     3035        double     xyz_list[NUMVERTICES][3];
     3036        double     dh1dh3[NDOF2][NUMVERTICES];
     3037        double     dk[NDOF2];
     3038        double     grade_g[NUMVERTICES]={0.0};
     3039        double     grade_g_gaussian[NUMVERTICES];
     3040        double     l1l2l3[3];
     3041        double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
     3042        Friction*  friction=NULL;
     3043        GaussTria  *gauss=NULL;
     3044
     3045        /*retrive parameters: */
     3046        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     3047
     3048        /*retrieve some parameters ands return if iceshelf: */
     3049        this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
     3050        if(IsOnShelf())return;
     3051        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3052        GetDofList1(&doflist1[0]);
     3053
     3054        /*Build frictoin element, needed later: */
     3055        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     3056        friction=new Friction("2d",inputs,matpar,analysis_type);
     3057
     3058        /*Retrieve all inputs we will be needing: */
     3059        Input* adjointx_input=inputs->GetInput(AdjointxEnum);               ISSMASSERT(adjointx_input);
     3060        Input* adjointy_input=inputs->GetInput(AdjointyEnum);               ISSMASSERT(adjointy_input);
     3061        Input* vx_input=inputs->GetInput(VxEnum);                           ISSMASSERT(vx_input);
     3062        Input* vy_input=inputs->GetInput(VyEnum);                           ISSMASSERT(vy_input);
     3063        Input* dragcoefficient_input=inputs->GetInput(DragCoefficientEnum); ISSMASSERT(dragcoefficient_input);
     3064
     3065        /* Start  looping on the number of gaussian points: */
     3066        gauss=new GaussTria(4);
     3067        for (ig=gauss->begin();ig<gauss->end();ig++){
     3068
     3069                gauss->GaussPoint(ig);
     3070
     3071                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     3072                GetNodalFunctions(l1l2l3, gauss);
     3073                GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
     3074
     3075                /*Build alpha_complement_list: */
     3076                if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
     3077                else alpha_complement=0;
     3078       
     3079                dragcoefficient_input->GetParameterValue(&drag, gauss);
     3080                adjointx_input->GetParameterValue(&lambda, gauss);
     3081                adjointy_input->GetParameterValue(&mu, gauss);
     3082                vx_input->GetParameterValue(&vx,gauss);
     3083                vy_input->GetParameterValue(&vy,gauss);
     3084                dragcoefficient_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
     3085
     3086                /*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
     3087                for (i=0;i<NUMVERTICES;i++){
     3088
     3089                        //standard term dJ/dki
     3090                        grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*l1l2l3[i];
     3091
     3092                        //noise dampening d/dki(1/2*(dk/dx)^2)
     3093                        grade_g_gaussian[i]+=-cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
     3094                }
     3095               
     3096                /*Add gradje_g_gaussian vector to gradje_g: */
     3097                for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
     3098        }
     3099
     3100        VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
     3101
     3102        /*Clean up and return*/
     3103        delete gauss;
     3104        delete friction;
     3105}
     3106/*}}}*/
     3107/*FUNCTION Tria::GradjDragStokes {{{1*/
     3108void  Tria::GradjDragStokes(Vec gradient){
     3109
     3110        int        i,ig;
     3111        int        drag_type,analysis_type;
     3112        int        doflist1[NUMVERTICES];
     3113        double     bed,thickness,Neff;
     3114        double     lambda,mu,xi,Jdet,vx,vy,vz;
     3115        double     alpha_complement,drag,cm_noisedmp;
     3116        double     surface_normal[3],bed_normal[3];
     3117        double     xyz_list[NUMVERTICES][3];
     3118        double     dh1dh3[NDOF2][NUMVERTICES];
     3119        double     dk[NDOF2];
     3120        double     l1l2l3[3];
     3121        double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
     3122        double     grade_g[NUMVERTICES]={0.0};
     3123        double     grade_g_gaussian[NUMVERTICES];
     3124        Friction*  friction=NULL;
     3125        GaussTria* gauss=NULL;
     3126
     3127        /*retrive parameters: */
     3128        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     3129
     3130        /*retrieve inputs :*/
     3131        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     3132        Input* drag_input    =inputs->GetInput(DragCoefficientEnum); ISSMASSERT(drag_input);
     3133        Input* vx_input      =inputs->GetInput(VxEnum);              ISSMASSERT(vx_input);
     3134        Input* vy_input      =inputs->GetInput(VyEnum);              ISSMASSERT(vy_input);
     3135        Input* vz_input      =inputs->GetInput(VzEnum);              ISSMASSERT(vz_input);
     3136        Input* adjointx_input=inputs->GetInput(AdjointxEnum);        ISSMASSERT(adjointx_input);
     3137        Input* adjointy_input=inputs->GetInput(AdjointyEnum);        ISSMASSERT(adjointy_input);
     3138        Input* adjointz_input=inputs->GetInput(AdjointzEnum);        ISSMASSERT(adjointz_input);
     3139
     3140        /*retrieve some parameters: */
     3141        this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
     3142
     3143        /*Get out if shelf*/
     3144        if(IsOnShelf())return;
     3145
     3146        /* Get node coordinates and dof list: */
     3147        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3148        GetDofList1(&doflist1[0]);
     3149
     3150        /*Build frictoin element, needed later: */
     3151        inputs->GetParameterValue(&drag_type,DragTypeEnum);
     3152        friction=new Friction("2d",inputs,matpar,analysis_type);
     3153
     3154        /* Start  looping on the number of gaussian points: */
     3155        gauss=new GaussTria(4);
     3156        for(ig=gauss->begin();ig<gauss->end();ig++){
     3157
     3158                gauss->GaussPoint(ig);
     3159
     3160                /*Recover alpha_complement and drag: */
     3161                if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
     3162                else alpha_complement=0;
     3163                drag_input->GetParameterValue(&drag,gauss);
     3164
     3165                /*recover lambda mu and xi: */
     3166                adjointx_input->GetParameterValue(&lambda,gauss);
     3167                adjointy_input->GetParameterValue(&mu    ,gauss);
     3168                adjointz_input->GetParameterValue(&xi    ,gauss);
     3169
     3170                /*recover vx vy and vz: */
     3171                vx_input->GetParameterValue(&vx, gauss);
     3172                vy_input->GetParameterValue(&vy, gauss);
     3173                vz_input->GetParameterValue(&vz, gauss);
     3174
     3175                /*Get normal vector to the bed */
     3176                SurfaceNormal(&surface_normal[0],xyz_list);
     3177
     3178                bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
     3179                bed_normal[1]=-surface_normal[1];
     3180                bed_normal[2]=-surface_normal[2];
     3181
     3182                /* Get Jacobian determinant: */
     3183                GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
     3184
     3185                /* Get nodal functions value at gaussian point:*/
     3186                GetNodalFunctions(l1l2l3, gauss);
     3187
     3188                /*Get nodal functions derivatives*/
     3189                GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
     3190
     3191                /*Get k derivative: dk/dx */
     3192                drag_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
     3193
     3194                /*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
     3195                for (i=0;i<NUMVERTICES;i++){
     3196                        //standard gradient dJ/dki
     3197                        grade_g_gaussian[i]=(
     3198                                                -lambda*(2*drag*alpha_complement*(vx - vz*bed_normal[0]*bed_normal[2]))
     3199                                                -mu    *(2*drag*alpha_complement*(vy - vz*bed_normal[1]*bed_normal[2]))
     3200                                                -xi    *(2*drag*alpha_complement*(-vx*bed_normal[0]*bed_normal[2]-vy*bed_normal[1]*bed_normal[2]))
     3201                                                )*Jdet*gauss->weight*l1l2l3[i];
     3202
     3203                        //Add regularization term
     3204                        grade_g_gaussian[i]+= - cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
     3205                }
     3206
     3207                /*Add gradje_g_gaussian vector to gradje_g: */
     3208                for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
     3209        }
     3210
     3211        VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
     3212
     3213        delete friction;
     3214        delete gauss;
     3215}
     3216/*}}}*/
     3217/*FUNCTION Tria::GradjDhDt{{{1*/
     3218void  Tria::GradjDhDt(Vec gradient){
     3219
     3220        /*Intermediaries*/
     3221        int    doflist1[NUMVERTICES];
     3222        double lambda[NUMVERTICES];
     3223        double gradient_g[NUMVERTICES];
     3224
     3225        GetDofList1(&doflist1[0]);
     3226
     3227        /*Compute Gradient*/
     3228        GetParameterListOnVertices(&lambda[0],AdjointEnum);
     3229        for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
     3230
     3231        VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)gradient_g,INSERT_VALUES);
     3232}
     3233/*}}}*/
     3234/*FUNCTION Tria::GradjVx{{{1*/
     3235void  Tria::GradjVx(Vec gradient){
     3236
     3237        /*Intermediaries*/
     3238        int        i,ig;
     3239        int        doflist1[NUMVERTICES];
     3240        double     thickness,Jdet,cm_noisedmp;
     3241        double     l1l2l3[3];
     3242        double     dbasis[NDOF2][NUMVERTICES];
     3243        double     Dlambda[2],dp[2];
     3244        double     xyz_list[NUMVERTICES][3];
     3245        double     grade_g[NUMVERTICES] = {0.0};
     3246        GaussTria *gauss                = NULL;
     3247
     3248        /* Get node coordinates and dof list: */
     3249        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3250        GetDofList1(&doflist1[0]);
     3251
     3252        /*Retrieve all inputs we will be needing: */
     3253        this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
     3254        Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
     3255        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     3256
     3257        /* Start  looping on the number of gaussian points: */
     3258        gauss=new GaussTria(2);
     3259        for (ig=gauss->begin();ig<gauss->end();ig++){
     3260
     3261                gauss->GaussPoint(ig);
     3262
     3263                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     3264                GetNodalFunctions(l1l2l3, gauss);
     3265                GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
     3266               
     3267                adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
     3268                thickness_input->GetParameterValue(&thickness, gauss);
     3269                thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
     3270
     3271                for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[0]*Jdet*gauss->weight*l1l2l3[i];
     3272
     3273                //noise dampening d/dki(1/2*(dk/dx)^2)
     3274                //for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
     3275        }
     3276
     3277        VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
     3278
     3279        /*Clean up and return*/
     3280        delete gauss;
     3281}
     3282/*}}}*/
     3283/*FUNCTION Tria::GradjVy{{{1*/
     3284void  Tria::GradjVy(Vec gradient){
     3285
     3286        /*Intermediaries*/
     3287        int        i,ig;
     3288        int        doflist1[NUMVERTICES];
     3289        double     thickness,Jdet,cm_noisedmp;
     3290        double     l1l2l3[3];
     3291        double     dbasis[NDOF2][NUMVERTICES];
     3292        double     Dlambda[2],dp[2];
     3293        double     xyz_list[NUMVERTICES][3];
     3294        double     grade_g[NUMVERTICES] = {0.0};
     3295        GaussTria *gauss                = NULL;
     3296
     3297        /* Get node coordinates and dof list: */
     3298        this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
     3299        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     3300        GetDofList1(&doflist1[0]);
     3301
     3302        /*Retrieve all inputs we will be needing: */
     3303        Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
     3304        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     3305
     3306        /* Start  looping on the number of gaussian points: */
     3307        gauss=new GaussTria(2);
     3308        for (ig=gauss->begin();ig<gauss->end();ig++){
     3309
     3310                gauss->GaussPoint(ig);
     3311
     3312                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     3313                GetNodalFunctions(l1l2l3, gauss);
     3314                GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
     3315
     3316                adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
     3317                thickness_input->GetParameterValue(&thickness, gauss);
     3318                thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
     3319
     3320                for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[1]*Jdet*gauss->weight*l1l2l3[i];
     3321
     3322                //noise dampening d/dki(1/2*(dk/dx)^2)
     3323                //for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
     3324        }
     3325
     3326        VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
     3327
     3328        /*Clean up and return*/
     3329        delete gauss;
     3330}
     3331/*}}}*/
     3332/*FUNCTION Tria::Id {{{1*/
     3333int    Tria::Id(){
     3334       
     3335        return id;
     3336
     3337}
     3338/*}}}*/
     3339/*FUNCTION Tria::InputArtificialNoise{{{1*/
     3340void  Tria::InputArtificialNoise(int enum_type,double min,double max){
     3341
     3342        Input* input=NULL;
     3343
     3344        /*Make a copy of the original input: */
     3345        input=(Input*)this->inputs->GetInput(enum_type);
     3346        if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
     3347
     3348        /*ArtificialNoise: */
     3349        input->ArtificialNoise(min,max);
     3350}
     3351/*}}}*/
     3352/*FUNCTION Tria::InputControlUpdate{{{1*/
     3353void  Tria::InputControlUpdate(double scalar,bool save_parameter){
     3354
     3355        /*Intermediary*/
     3356        int    num_controls;
     3357        int*   control_type=NULL;
     3358        Input* input=NULL;
     3359        double *cm_min=NULL;
     3360        double *cm_max=NULL;
     3361
     3362        /*retrieve some parameters: */
     3363        this->parameters->FindParam(&cm_min,NULL,CmMinEnum);
     3364        this->parameters->FindParam(&cm_max,NULL,CmMaxEnum);
     3365        this->parameters->FindParam(&num_controls,NumControlsEnum);
     3366        this->parameters->FindParam(&control_type,NULL,ControlTypeEnum);
     3367
     3368        for(int i=0;i<num_controls;i++){
     3369
     3370                if(control_type[i]==RheologyBbarEnum){
     3371                        input=(Input*)matice->inputs->GetInput(control_type[i]); ISSMASSERT(input);
     3372                }
     3373                else{
     3374                        input=(Input*)this->inputs->GetInput(control_type[i]);   ISSMASSERT(input);
     3375                }
     3376
     3377                if (input->Enum()!=ControlInputEnum){
     3378                        ISSMERROR("input %s is not a ControlInput",EnumToString(control_type[i]));
     3379                }
     3380
     3381                ((ControlInput*)input)->UpdateValue(scalar);
     3382                input->Constrain(cm_min[i],cm_max[i]);
     3383                if (save_parameter) ((ControlInput*)input)->SaveValue();
     3384
     3385        }
     3386
     3387        /*Clean up and return*/
     3388        xfree((void**)&control_type);
     3389        xfree((void**)&cm_min);
     3390        xfree((void**)&cm_max);
     3391}
     3392/*}}}*/
     3393/*FUNCTION Tria::InputConvergence{{{1*/
     3394bool Tria::InputConvergence(double* eps, int* enums,int num_enums,int* criterionenums,double* criterionvalues,int num_criterionenums){
     3395
     3396        bool    converged=true;
     3397        int     i;
     3398        Input** new_inputs=NULL;
     3399        Input** old_inputs=NULL;
     3400
     3401        new_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the new inputs
     3402        old_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the old inputs
     3403
     3404        for(i=0;i<num_enums/2;i++){
     3405                new_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+0]);
     3406                old_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+1]);
     3407                if(!new_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
     3408                if(!old_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
     3409        }
     3410
     3411        /*ok, we've got the inputs (new and old), now loop throught the number of criterions and fill the eps array:*/
     3412        for(i=0;i<num_criterionenums;i++){
     3413                IsInputConverged(eps+i,new_inputs,old_inputs,num_enums/2,criterionenums[i]);
     3414                if(eps[i]>criterionvalues[i]) converged=false;
     3415        }
     3416
     3417        /*clean up and return*/
     3418        xfree((void**)&new_inputs);
     3419        xfree((void**)&old_inputs);
     3420        return converged;
     3421}
     3422/*}}}*/
     3423/*FUNCTION Tria::InputDepthAverageAtBase {{{1*/
     3424void  Tria::InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum){
     3425
     3426        /*New input*/
     3427        Input* oldinput=NULL;
     3428        Input* newinput=NULL;
     3429
     3430        /*copy input of enum_type*/
     3431        if (object_enum==ElementsEnum)
     3432         oldinput=(Input*)this->inputs->GetInput(enum_type);
     3433        else if (object_enum==MaterialsEnum)
     3434         oldinput=(Input*)this->matice->inputs->GetInput(enum_type);
     3435        else
     3436         ISSMERROR("object %s not supported yet",EnumToString(object_enum));
     3437        if(!oldinput)ISSMERROR("%s%s"," could not find old input with enum: ",EnumToString(enum_type));
     3438        newinput=(Input*)oldinput->copy();
     3439
     3440        /*Assign new name (average)*/
     3441        newinput->ChangeEnum(average_enum_type);
     3442
     3443        /*Add new input to current element*/
     3444        if (object_enum==ElementsEnum)
     3445         this->inputs->AddInput((Input*)newinput);
     3446        else if (object_enum==MaterialsEnum)
     3447         this->matice->inputs->AddInput((Input*)newinput);
     3448        else
     3449         ISSMERROR("object %s not supported yet",EnumToString(object_enum));
     3450}
     3451/*}}}*/
     3452/*FUNCTION Tria::InputDuplicate{{{1*/
     3453void  Tria::InputDuplicate(int original_enum,int new_enum){
     3454
     3455        /*Call inputs method*/
     3456        if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
     3457
     3458}
     3459/*}}}*/
     3460/*FUNCTION Tria::InputScale{{{1*/
     3461void  Tria::InputScale(int enum_type,double scale_factor){
     3462
     3463        Input* input=NULL;
     3464
     3465        /*Make a copy of the original input: */
     3466        input=(Input*)this->inputs->GetInput(enum_type);
     3467        if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
     3468
     3469        /*Scale: */
     3470        input->Scale(scale_factor);
     3471}
     3472/*}}}*/
     3473/*FUNCTION Tria::InputToResult{{{1*/
     3474void  Tria::InputToResult(int enum_type,int step,double time){
     3475
     3476        int    i;
     3477        Input *input = NULL;
     3478
     3479        /*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
     3480        if (enum_type==RheologyBbarEnum) input=this->matice->inputs->GetInput(enum_type);
     3481        else input=this->inputs->GetInput(enum_type);
     3482        if (!input) ISSMERROR("Input %s not found in tria->inputs",EnumToString(enum_type));
     3483
     3484        /*If we don't find it, no big deal, just don't do the transfer. Otherwise, build a new Result
     3485         * object out of the input, with the additional step and time information: */
     3486        this->results->AddObject((Object*)input->SpawnResult(step,time));
     3487        if(input->Enum()==ControlInputEnum) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
     3488}
     3489/*}}}*/
    3393490/*FUNCTION Tria::InputUpdateFromConstant(int value, int name);{{{1*/
    3403491void  Tria::InputUpdateFromConstant(int constant, int name){
     
    3623513        /*update input*/
    3633514        this->inputs->AddInput(new BoolInput(name,constant));
     3515}
     3516/*}}}*/
     3517/*FUNCTION Tria::InputUpdateFromIoModel{{{1*/
     3518void Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){ //i is the element index
     3519
     3520        /*Intermediaries*/
     3521        int    i,j;
     3522        int    tria_vertex_ids[3];
     3523        double nodeinputs[3];
     3524
     3525        /*Checks if debuging*/
     3526        /*{{{2*/
     3527        ISSMASSERT(iomodel->elements);
     3528        /*}}}*/
     3529
     3530        /*Recover vertices ids needed to initialize inputs*/
     3531        for(i=0;i<3;i++){
     3532                tria_vertex_ids[i]=(int)iomodel->elements[3*index+i]; //ids for vertices are in the elements array from Matlab
     3533        }
     3534
     3535        /*add as many inputs per element as requested:*/
     3536        if (iomodel->thickness) {
     3537                for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness[tria_vertex_ids[i]-1];
     3538                this->inputs->AddInput(new TriaVertexInput(ThicknessEnum,nodeinputs));
     3539        }
     3540        if (iomodel->surface) {
     3541                for(i=0;i<3;i++)nodeinputs[i]=iomodel->surface[tria_vertex_ids[i]-1];
     3542                this->inputs->AddInput(new TriaVertexInput(SurfaceEnum,nodeinputs));
     3543        }
     3544        if (iomodel->bed) {
     3545                for(i=0;i<3;i++)nodeinputs[i]=iomodel->bed[tria_vertex_ids[i]-1];
     3546                this->inputs->AddInput(new TriaVertexInput(BedEnum,nodeinputs));
     3547        }
     3548        if (iomodel->drag_coefficient) {
     3549                for(i=0;i<3;i++)nodeinputs[i]=iomodel->drag_coefficient[tria_vertex_ids[i]-1];
     3550                this->inputs->AddInput(new TriaVertexInput(DragCoefficientEnum,nodeinputs));
     3551
     3552                if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
     3553                if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
     3554                this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
     3555        }
     3556        if (iomodel->thickness_obs) {
     3557                for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness_obs[tria_vertex_ids[i]-1];
     3558                this->inputs->AddInput(new TriaVertexInput(ThicknessObsEnum,nodeinputs));
     3559        }
     3560        if (iomodel->melting_rate) {
     3561                for(i=0;i<3;i++)nodeinputs[i]=iomodel->melting_rate[tria_vertex_ids[i]-1]/iomodel->yts;
     3562                this->inputs->AddInput(new TriaVertexInput(MeltingRateEnum,nodeinputs));
     3563        }
     3564        if (iomodel->accumulation_rate) {
     3565                for(i=0;i<3;i++)nodeinputs[i]=iomodel->accumulation_rate[tria_vertex_ids[i]-1]/iomodel->yts;
     3566                this->inputs->AddInput(new TriaVertexInput(AccumulationRateEnum,nodeinputs));
     3567        }
     3568        if (iomodel->geothermalflux) {
     3569                for(i=0;i<3;i++)nodeinputs[i]=iomodel->geothermalflux[tria_vertex_ids[i]-1];
     3570                this->inputs->AddInput(new TriaVertexInput(GeothermalFluxEnum,nodeinputs));
     3571        }
     3572        if (iomodel->dhdt){
     3573                for(i=0;i<3;i++)nodeinputs[i]=iomodel->dhdt[tria_vertex_ids[i]-1]/iomodel->yts;
     3574                this->inputs->AddInput(new TriaVertexInput(DhDtEnum,nodeinputs));
     3575        }
     3576        if (iomodel->pressure){
     3577                for(i=0;i<3;i++)nodeinputs[i]=iomodel->pressure[tria_vertex_ids[i]-1];
     3578                this->inputs->AddInput(new TriaVertexInput(PressureEnum,nodeinputs));
     3579        }
     3580        if (iomodel->temperature) {
     3581                for(i=0;i<3;i++)nodeinputs[i]=iomodel->temperature[tria_vertex_ids[i]-1];
     3582                this->inputs->AddInput(new TriaVertexInput(TemperatureEnum,nodeinputs));
     3583        }
     3584        /*vx,vy and vz: */
     3585        if (iomodel->vx) {
     3586                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx[tria_vertex_ids[i]-1]/iomodel->yts;
     3587                this->inputs->AddInput(new TriaVertexInput(VxEnum,nodeinputs));
     3588                this->inputs->AddInput(new TriaVertexInput(VxOldEnum,nodeinputs));
     3589                if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVxEnum,nodeinputs));
     3590        }
     3591        if (iomodel->vy) {
     3592                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy[tria_vertex_ids[i]-1]/iomodel->yts;
     3593                this->inputs->AddInput(new TriaVertexInput(VyEnum,nodeinputs));
     3594                this->inputs->AddInput(new TriaVertexInput(VyOldEnum,nodeinputs));
     3595                if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVyEnum,nodeinputs));
     3596        }
     3597        if (iomodel->vz) {
     3598                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz[tria_vertex_ids[i]-1]/iomodel->yts;
     3599                this->inputs->AddInput(new TriaVertexInput(VzEnum,nodeinputs));
     3600                this->inputs->AddInput(new TriaVertexInput(VzOldEnum,nodeinputs));
     3601                if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVzEnum,nodeinputs));
     3602        }
     3603        if (iomodel->vx_obs) {
     3604                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx_obs[tria_vertex_ids[i]-1]/iomodel->yts;
     3605                this->inputs->AddInput(new TriaVertexInput(VxObsEnum,nodeinputs));
     3606        }
     3607        if (iomodel->vy_obs) {
     3608                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy_obs[tria_vertex_ids[i]-1]/iomodel->yts;
     3609                this->inputs->AddInput(new TriaVertexInput(VyObsEnum,nodeinputs));
     3610        }
     3611        if (iomodel->vz_obs) {
     3612                for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz_obs[tria_vertex_ids[i]-1]/iomodel->yts;
     3613                this->inputs->AddInput(new TriaVertexInput(VzObsEnum,nodeinputs));
     3614        }
     3615        if (iomodel->weights) {
     3616                for(i=0;i<3;i++)nodeinputs[i]=iomodel->weights[tria_vertex_ids[i]-1];
     3617                this->inputs->AddInput(new TriaVertexInput(WeightsEnum,nodeinputs));
     3618        }
     3619        if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
     3620        if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
     3621        if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
     3622        if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
     3623
     3624        /*time: */
     3625        this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
     3626
     3627        /*Control Inputs*/
     3628        if (iomodel->control_analysis && iomodel->control_type){
     3629                for(i=0;i<iomodel->num_control_type;i++){
     3630                        switch((int)iomodel->control_type[i]){
     3631                                case DhDtEnum:
     3632                                        if (iomodel->dhdt){
     3633                                                for(j=0;j<3;j++)nodeinputs[j]=iomodel->dhdt[tria_vertex_ids[j]-1]/iomodel->yts;
     3634                                                this->inputs->AddInput(new ControlInput(DhDtEnum,TriaVertexInputEnum,nodeinputs,i+1));
     3635                                        }
     3636                                        break;
     3637                                case VxEnum:
     3638                                        if (iomodel->vx){
     3639                                                for(j=0;j<3;j++)nodeinputs[j]=iomodel->vx[tria_vertex_ids[j]-1]/iomodel->yts;
     3640                                                this->inputs->AddInput(new ControlInput(VxEnum,TriaVertexInputEnum,nodeinputs,i+1));
     3641                                        }
     3642                                        break;
     3643                                case VyEnum:
     3644                                        if (iomodel->vy){
     3645                                                for(j=0;j<3;j++)nodeinputs[j]=iomodel->vy[tria_vertex_ids[j]-1]/iomodel->yts;
     3646                                                this->inputs->AddInput(new ControlInput(VyEnum,TriaVertexInputEnum,nodeinputs,i+1));
     3647                                        }
     3648                                        break;
     3649                                case DragCoefficientEnum:
     3650                                        if (iomodel->drag_coefficient){
     3651                                                for(j=0;j<3;j++)nodeinputs[j]=iomodel->drag_coefficient[tria_vertex_ids[j]-1];
     3652                                                this->inputs->AddInput(new ControlInput(DragCoefficientEnum,TriaVertexInputEnum,nodeinputs,i+1));
     3653                                        }
     3654                                        break;
     3655                                case RheologyBbarEnum:
     3656                                        /*Matice will take care of it*/ break;
     3657                                default:
     3658                                        ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
     3659                        }
     3660                }
     3661        }
    3643662}
    3653663/*}}}*/
     
    4113709}
    4123710/*}}}*/
     3711/*FUNCTION Tria::InputUpdateFromSolutionAdjointBalancedthickness {{{1*/
     3712void  Tria::InputUpdateFromSolutionAdjointBalancedthickness(double* solution){
     3713
     3714        const int numdof=NDOF1*NUMVERTICES;
     3715
     3716        int       i;
     3717        int*      doflist=NULL;
     3718        double    values[numdof];
     3719        double    lambda[NUMVERTICES];
     3720
     3721        /*Get dof list: */
     3722        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3723
     3724        /*Use the dof list to index into the solution vector: */
     3725        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3726
     3727        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3728        for(i=0;i<numdof;i++) lambda[i]=values[i];
     3729
     3730        /*Add vx and vy as inputs to the tria element: */
     3731        this->inputs->AddInput(new TriaVertexInput(AdjointEnum,lambda));
     3732
     3733        /*Free ressources:*/
     3734        xfree((void**)&doflist);
     3735}
     3736/*}}}*/
     3737/*FUNCTION Tria::InputUpdateFromSolutionAdjointHoriz {{{1*/
     3738void  Tria::InputUpdateFromSolutionAdjointHoriz(double* solution){
     3739
     3740        const int numdof=NDOF2*NUMVERTICES;
     3741
     3742        int       i;
     3743        int*      doflist=NULL;
     3744        double    values[numdof];
     3745        double    lambdax[NUMVERTICES];
     3746        double    lambday[NUMVERTICES];
     3747
     3748        /*Get dof list: */
     3749        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3750
     3751        /*Use the dof list to index into the solution vector: */
     3752        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3753
     3754        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3755        for(i=0;i<NUMVERTICES;i++){
     3756                lambdax[i]=values[i*NDOF2+0];
     3757                lambday[i]=values[i*NDOF2+1];
     3758        }
     3759
     3760        /*Add vx and vy as inputs to the tria element: */
     3761        this->inputs->AddInput(new TriaVertexInput(AdjointxEnum,lambdax));
     3762        this->inputs->AddInput(new TriaVertexInput(AdjointyEnum,lambday));
     3763
     3764        /*Free ressources:*/
     3765        xfree((void**)&doflist);
     3766}
     3767/*}}}*/
     3768/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
     3769void  Tria::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
     3770       
     3771        const int numdof=NDOF2*NUMVERTICES;
     3772
     3773        int       i;
     3774        int       dummy;
     3775        int*      doflist=NULL;
     3776        double    rho_ice,g;
     3777        double    values[numdof];
     3778        double    vx[NUMVERTICES];
     3779        double    vy[NUMVERTICES];
     3780        double    vz[NUMVERTICES];
     3781        double    vel[NUMVERTICES];
     3782        double    pressure[NUMVERTICES];
     3783        double    thickness[NUMVERTICES];
     3784       
     3785        /*Get dof list: */
     3786        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3787
     3788        /*Use the dof list to index into the solution vector: */
     3789        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3790
     3791        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3792        for(i=0;i<NUMVERTICES;i++){
     3793                vx[i]=values[i*NDOF2+0];
     3794                vy[i]=values[i*NDOF2+1];
     3795        }
     3796
     3797        /*Get Vz and compute vel*/
     3798        GetParameterListOnVertices(&vz[0],VzEnum,0);
     3799        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     3800
     3801        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D,
     3802         *so the pressure is just the pressure at the bedrock: */
     3803        rho_ice=matpar->GetRhoIce();
     3804        g=matpar->GetG();
     3805        GetParameterListOnVertices(&thickness[0],ThicknessEnum);
     3806        for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
     3807
     3808        /*Now, we have to move the previous Vx and Vy inputs  to old
     3809         * status, otherwise, we'll wipe them off: */
     3810        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     3811        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     3812        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     3813
     3814        /*Add vx and vy as inputs to the tria element: */
     3815        this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
     3816        this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
     3817        this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
     3818        this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
     3819
     3820        /*Free ressources:*/
     3821        xfree((void**)&doflist);
     3822
     3823}
     3824/*}}}*/
     3825/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHutter {{{1*/
     3826void  Tria::InputUpdateFromSolutionDiagnosticHutter(double* solution){
     3827       
     3828        const int numdof=NDOF2*NUMVERTICES;
     3829       
     3830        int       i;
     3831        int       dummy;
     3832        int*      doflist=NULL;
     3833        double    rho_ice,g;
     3834        double    values[numdof];
     3835        double    vx[NUMVERTICES];
     3836        double    vy[NUMVERTICES];
     3837        double    vz[NUMVERTICES];
     3838        double    vel[NUMVERTICES];
     3839        double    pressure[NUMVERTICES];
     3840        double    thickness[NUMVERTICES];
     3841        double*   vz_ptr=NULL;
     3842        Input*    vz_input=NULL;
     3843       
     3844        /*Get dof list: */
     3845        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3846
     3847        /*Use the dof list to index into the solution vector: */
     3848        for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3849
     3850        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     3851        for(i=0;i<NUMVERTICES;i++){
     3852                vx[i]=values[i*NDOF2+0];
     3853                vy[i]=values[i*NDOF2+1];
     3854        }
     3855
     3856        /*Get Vz*/
     3857        vz_input=inputs->GetInput(VzEnum);
     3858        if (vz_input){
     3859                if (vz_input->Enum()!=TriaVertexInputEnum){
     3860                        ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
     3861                }
     3862                vz_input->GetValuesPtr(&vz_ptr,&dummy);
     3863                for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
     3864        }
     3865        else{
     3866                for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
     3867        }
     3868
     3869        /*Now Compute vel*/
     3870        for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
     3871
     3872        /*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D,
     3873         *so the pressure is just the pressure at the bedrock: */
     3874        rho_ice=matpar->GetRhoIce();
     3875        g=matpar->GetG();
     3876        GetParameterListOnVertices(&thickness[0],ThicknessEnum);
     3877        for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
     3878
     3879        /*Now, we have to move the previous Vx and Vy inputs  to old
     3880         * status, otherwise, we'll wipe them off: */
     3881        this->inputs->ChangeEnum(VxEnum,VxOldEnum);
     3882        this->inputs->ChangeEnum(VyEnum,VyOldEnum);
     3883        this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
     3884
     3885        /*Add vx and vy as inputs to the tria element: */
     3886        this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
     3887        this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
     3888        this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
     3889        this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
     3890
     3891        /*Free ressources:*/
     3892        xfree((void**)&doflist);
     3893}
     3894/*}}}*/
     3895/*FUNCTION Tria::InputUpdateFromSolutionOneDof{{{1*/
     3896void  Tria::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
     3897
     3898        const int numdof          = NDOF1*NUMVERTICES;
     3899
     3900        int*      doflist=NULL;
     3901        double    values[numdof];
     3902
     3903        /*Get dof list: */
     3904        GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
     3905
     3906        /*Use the dof list to index into the solution vector: */
     3907        for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
     3908
     3909        /*Add input to the element: */
     3910        this->inputs->AddInput(new TriaVertexInput(enum_type,values));
     3911
     3912        /*Free ressources:*/
     3913        xfree((void**)&doflist);
     3914}
     3915/*}}}*/
    4133916/*FUNCTION Tria::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
    4143917void  Tria::InputUpdateFromVector(double* vector, int name, int type){
     
    5354038}
    5364039/*}}}*/
    537 /*FUNCTION Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){{{1*/
    538 void Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){ //i is the element index
    539 
    540         /*Intermediaries*/
    541         int    i,j;
    542         int    tria_vertex_ids[3];
    543         double nodeinputs[3];
    544 
    545         /*Checks if debuging*/
    546         /*{{{2*/
    547         ISSMASSERT(iomodel->elements);
    548         /*}}}*/
    549 
    550         /*Recover vertices ids needed to initialize inputs*/
    551         for(i=0;i<3;i++){
    552                 tria_vertex_ids[i]=(int)iomodel->elements[3*index+i]; //ids for vertices are in the elements array from Matlab
    553         }
    554 
    555         /*add as many inputs per element as requested:*/
    556         if (iomodel->thickness) {
    557                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness[tria_vertex_ids[i]-1];
    558                 this->inputs->AddInput(new TriaVertexInput(ThicknessEnum,nodeinputs));
    559         }
    560         if (iomodel->surface) {
    561                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->surface[tria_vertex_ids[i]-1];
    562                 this->inputs->AddInput(new TriaVertexInput(SurfaceEnum,nodeinputs));
    563         }
    564         if (iomodel->bed) {
    565                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->bed[tria_vertex_ids[i]-1];
    566                 this->inputs->AddInput(new TriaVertexInput(BedEnum,nodeinputs));
    567         }
    568         if (iomodel->drag_coefficient) {
    569                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->drag_coefficient[tria_vertex_ids[i]-1];
    570                 this->inputs->AddInput(new TriaVertexInput(DragCoefficientEnum,nodeinputs));
    571 
    572                 if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
    573                 if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
    574                 this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
    575         }
    576         if (iomodel->thickness_obs) {
    577                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness_obs[tria_vertex_ids[i]-1];
    578                 this->inputs->AddInput(new TriaVertexInput(ThicknessObsEnum,nodeinputs));
    579         }
    580         if (iomodel->melting_rate) {
    581                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->melting_rate[tria_vertex_ids[i]-1]/iomodel->yts;
    582                 this->inputs->AddInput(new TriaVertexInput(MeltingRateEnum,nodeinputs));
    583         }
    584         if (iomodel->accumulation_rate) {
    585                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->accumulation_rate[tria_vertex_ids[i]-1]/iomodel->yts;
    586                 this->inputs->AddInput(new TriaVertexInput(AccumulationRateEnum,nodeinputs));
    587         }
    588         if (iomodel->geothermalflux) {
    589                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->geothermalflux[tria_vertex_ids[i]-1];
    590                 this->inputs->AddInput(new TriaVertexInput(GeothermalFluxEnum,nodeinputs));
    591         }
    592         if (iomodel->dhdt){
    593                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->dhdt[tria_vertex_ids[i]-1]/iomodel->yts;
    594                 this->inputs->AddInput(new TriaVertexInput(DhDtEnum,nodeinputs));
    595         }
    596         if (iomodel->pressure){
    597                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->pressure[tria_vertex_ids[i]-1];
    598                 this->inputs->AddInput(new TriaVertexInput(PressureEnum,nodeinputs));
    599         }
    600         if (iomodel->temperature) {
    601                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->temperature[tria_vertex_ids[i]-1];
    602                 this->inputs->AddInput(new TriaVertexInput(TemperatureEnum,nodeinputs));
    603         }
    604         /*vx,vy and vz: */
    605         if (iomodel->vx) {
    606                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx[tria_vertex_ids[i]-1]/iomodel->yts;
    607                 this->inputs->AddInput(new TriaVertexInput(VxEnum,nodeinputs));
    608                 this->inputs->AddInput(new TriaVertexInput(VxOldEnum,nodeinputs));
    609                 if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVxEnum,nodeinputs));
    610         }
    611         if (iomodel->vy) {
    612                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy[tria_vertex_ids[i]-1]/iomodel->yts;
    613                 this->inputs->AddInput(new TriaVertexInput(VyEnum,nodeinputs));
    614                 this->inputs->AddInput(new TriaVertexInput(VyOldEnum,nodeinputs));
    615                 if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVyEnum,nodeinputs));
    616         }
    617         if (iomodel->vz) {
    618                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz[tria_vertex_ids[i]-1]/iomodel->yts;
    619                 this->inputs->AddInput(new TriaVertexInput(VzEnum,nodeinputs));
    620                 this->inputs->AddInput(new TriaVertexInput(VzOldEnum,nodeinputs));
    621                 if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVzEnum,nodeinputs));
    622         }
    623         if (iomodel->vx_obs) {
    624                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx_obs[tria_vertex_ids[i]-1]/iomodel->yts;
    625                 this->inputs->AddInput(new TriaVertexInput(VxObsEnum,nodeinputs));
    626         }
    627         if (iomodel->vy_obs) {
    628                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy_obs[tria_vertex_ids[i]-1]/iomodel->yts;
    629                 this->inputs->AddInput(new TriaVertexInput(VyObsEnum,nodeinputs));
    630         }
    631         if (iomodel->vz_obs) {
    632                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz_obs[tria_vertex_ids[i]-1]/iomodel->yts;
    633                 this->inputs->AddInput(new TriaVertexInput(VzObsEnum,nodeinputs));
    634         }
    635         if (iomodel->weights) {
    636                 for(i=0;i<3;i++)nodeinputs[i]=iomodel->weights[tria_vertex_ids[i]-1];
    637                 this->inputs->AddInput(new TriaVertexInput(WeightsEnum,nodeinputs));
    638         }
    639         if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
    640         if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
    641         if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
    642         if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
    643 
    644         /*time: */
    645         this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
    646 
    647         /*Control Inputs*/
    648         if (iomodel->control_analysis && iomodel->control_type){
    649                 for(i=0;i<iomodel->num_control_type;i++){
    650                         switch((int)iomodel->control_type[i]){
    651                                 case DhDtEnum:
    652                                         if (iomodel->dhdt){
    653                                                 for(j=0;j<3;j++)nodeinputs[j]=iomodel->dhdt[tria_vertex_ids[j]-1]/iomodel->yts;
    654                                                 this->inputs->AddInput(new ControlInput(DhDtEnum,TriaVertexInputEnum,nodeinputs,i+1));
    655                                         }
    656                                         break;
    657                                 case VxEnum:
    658                                         if (iomodel->vx){
    659                                                 for(j=0;j<3;j++)nodeinputs[j]=iomodel->vx[tria_vertex_ids[j]-1]/iomodel->yts;
    660                                                 this->inputs->AddInput(new ControlInput(VxEnum,TriaVertexInputEnum,nodeinputs,i+1));
    661                                         }
    662                                         break;
    663                                 case VyEnum:
    664                                         if (iomodel->vy){
    665                                                 for(j=0;j<3;j++)nodeinputs[j]=iomodel->vy[tria_vertex_ids[j]-1]/iomodel->yts;
    666                                                 this->inputs->AddInput(new ControlInput(VyEnum,TriaVertexInputEnum,nodeinputs,i+1));
    667                                         }
    668                                         break;
    669                                 case DragCoefficientEnum:
    670                                         if (iomodel->drag_coefficient){
    671                                                 for(j=0;j<3;j++)nodeinputs[j]=iomodel->drag_coefficient[tria_vertex_ids[j]-1];
    672                                                 this->inputs->AddInput(new ControlInput(DragCoefficientEnum,TriaVertexInputEnum,nodeinputs,i+1));
    673                                         }
    674                                         break;
    675                                 case RheologyBbarEnum:
    676                                         /*Matice will take care of it*/ break;
    677                                 default:
    678                                         ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
    679                         }
    680                 }
    681         }
    682 }
    683 /*}}}*/
    684 
    685 /*Element virtual functions definitions: */
    686 /*FUNCTION Tria::AverageOntoPartition {{{1*/
    687 void  Tria::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
    688 
    689         bool      already=false;
    690         int       i,j;
    691         int       partition[NUMVERTICES];
    692         int       offsetsid[NUMVERTICES];
    693         int       offsetdof[NUMVERTICES];
    694         double    area;
    695         double    mean;
    696         double    values[3];
    697 
    698         /*First, get the area: */
    699         area=this->GetArea();
    700 
    701         /*Figure out the average for this element: */
    702         this->GetSidList(&offsetsid[0]);
    703         this->GetDofList1(&offsetdof[0]);
    704         mean=0;
    705         for(i=0;i<NUMVERTICES;i++){
    706                 partition[i]=(int)qmu_part[offsetsid[i]];
    707                 mean=mean+1.0/NUMVERTICES*vertex_response[offsetdof[i]];
    708         }
    709 
    710         /*Add contribution: */
    711         for(i=0;i<NUMVERTICES;i++){
    712                 already=false;
    713                 for(j=0;j<i;j++){
    714                         if (partition[i]==partition[j]){
    715                                 already=true;
    716                                 break;
    717                         }
    718                 }
    719                 if(!already){
    720                         VecSetValue(partition_contributions,partition[i],mean*area,ADD_VALUES);
    721                         VecSetValue(partition_areas,partition[i],area,ADD_VALUES);
    722                 };
    723         }
    724 }
    725 /*}}}*/
    726 /*FUNCTION Tria::ComputeBasalStress {{{1*/
    727 void  Tria::ComputeBasalStress(Vec eps){
    728         ISSMERROR("Not Implemented yet");
    729 }
    730 /*}}}*/
    731 /*FUNCTION Tria::ComputeStrainRate {{{1*/
    732 void  Tria::ComputeStrainRate(Vec eps){
    733         ISSMERROR("Not Implemented yet");
    734 }
    735 /*}}}*/
    736 /*FUNCTION Tria::SetCurrentConfiguration {{{1*/
    737 void  Tria::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
     4040/*FUNCTION Tria::IsInput{{{1*/
     4041bool Tria::IsInput(int name){
     4042        if (
     4043                                name==ThicknessEnum ||
     4044                                name==SurfaceEnum ||
     4045                                name==BedEnum ||
     4046                                name==SurfaceSlopeXEnum ||
     4047                                name==SurfaceSlopeYEnum ||
     4048                                name==MeltingRateEnum ||
     4049                                name==DtEnum ||
     4050                                name==AccumulationRateEnum ||
     4051                                name==SurfaceAreaEnum||
     4052                                name==VxEnum ||
     4053                                name==VyEnum ||
     4054                                name==VxObsEnum ||
     4055                                name==VyObsEnum ||
     4056                                name==CmResponseEnum ||
     4057                                name==DragCoefficientEnum ||
     4058                                name==GradientEnum ||
     4059                                name==OldGradientEnum
     4060                ){
     4061                return true;
     4062        }
     4063        else return false;
     4064}
     4065/*}}}*/
     4066/*FUNCTION Tria::IsOnBed {{{1*/
     4067bool Tria::IsOnBed(){
    7384068       
    739         /*go into parameters and get the analysis_counter: */
    740         int analysis_counter;
    741         parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
    742 
    743         /*Get Element type*/
    744         this->element_type=this->element_type_list[analysis_counter];
    745 
    746         /*Pick up nodes*/
    747         if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
    748         else this->nodes=NULL;
    749 
    750 }
    751 /*}}}*/
    752 /*FUNCTION Tria::Configure {{{1*/
    753 void  Tria::Configure(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
    754        
    755         /*go into parameters and get the analysis_counter: */
    756         int analysis_counter;
    757         parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
    758 
    759         /*Get Element type*/
    760         this->element_type=this->element_type_list[analysis_counter];
    761 
    762         /*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective
    763          * datasets, using internal ids and offsets hidden in hooks: */
    764         if(this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
    765         this->hmatice->configure(materialsin);
    766         this->hmatpar->configure(materialsin);
    767 
    768         /*Now, go pick up the objects inside the hooks: */
    769         if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
    770         else this->nodes=NULL;
    771         this->matice=(Matice*)this->hmatice->delivers();
    772         this->matpar=(Matpar*)this->hmatpar->delivers();
    773 
    774         /*point parameters to real dataset: */
    775         this->parameters=parametersin;
    776 
    777 }
    778 /*}}}*/
    779 /*FUNCTION Tria::ControlInputGetGradient{{{1*/
    780 void Tria::ControlInputGetGradient(Vec gradient,int enum_type){
    781 
    782         int doflist1[NUMVERTICES];
    783         Input* input=NULL;
    784 
    785         if(enum_type==RheologyBbarEnum){
    786                 input=(Input*)matice->inputs->GetInput(enum_type);
    787         }
    788         else{
    789                 input=inputs->GetInput(enum_type);
    790         }
    791         if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
    792         if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
    793 
    794         this->GetDofList1(&doflist1[0]);
    795         ((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
    796 
    797 }/*}}}*/
    798 /*FUNCTION Tria::ControlInputScaleGradient{{{1*/
    799 void Tria::ControlInputScaleGradient(int enum_type,double scale){
    800 
    801         Input* input=NULL;
    802 
    803         if(enum_type==RheologyBbarEnum){
    804                 input=(Input*)matice->inputs->GetInput(enum_type);
    805         }
    806         else{
    807                 input=inputs->GetInput(enum_type);
    808         }
    809         if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
    810         if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
    811 
    812         ((ControlInput*)input)->ScaleGradient(scale);
    813 }/*}}}*/
    814 /*FUNCTION Tria::ControlInputSetGradient{{{1*/
    815 void Tria::ControlInputSetGradient(double* gradient,int enum_type){
    816 
    817         int    doflist1[NUMVERTICES];
    818         double grad_list[NUMVERTICES];
    819         Input* grad_input=NULL;
    820         Input* input=NULL;
    821 
    822         if(enum_type==RheologyBbarEnum){
    823                 input=(Input*)matice->inputs->GetInput(enum_type);
    824         }
    825         else{
    826                 input=inputs->GetInput(enum_type);
    827         }
    828         if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
    829         if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
    830 
    831         this->GetDofList1(&doflist1[0]);
    832         for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[i]];
    833         grad_input=new TriaVertexInput(GradientEnum,grad_list);
    834 
    835         ((ControlInput*)input)->SetGradient(grad_input);
    836 
    837 }/*}}}*/
     4069        bool onbed;
     4070        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     4071        return onbed;
     4072}
     4073/*}}}*/
     4074/*FUNCTION Tria::IsOnShelf {{{1*/
     4075bool   Tria::IsOnShelf(){
     4076
     4077        bool shelf;
     4078        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     4079        return shelf;
     4080}
     4081/*}}}*/
     4082/*FUNCTION Tria::IsOnWater {{{1*/
     4083bool   Tria::IsOnWater(){
     4084
     4085        bool water;
     4086        inputs->GetParameterValue(&water,ElementOnWaterEnum);
     4087        return water;
     4088}
     4089/*}}}*/
     4090/*FUNCTION Tria::MassFlux {{{1*/
     4091double Tria::MassFlux( double* segment,bool process_units){
     4092
     4093        const int    numdofs=2;
     4094
     4095        int        i;
     4096        double     mass_flux=0;
     4097        double     xyz_list[NUMVERTICES][3];
     4098        double     normal[2];
     4099        double     length,rho_ice;
     4100        double     x1,y1,x2,y2,h1,h2;
     4101        double     vx1,vx2,vy1,vy2;
     4102        GaussTria* gauss_1=NULL;
     4103        GaussTria* gauss_2=NULL;
     4104
     4105        /*Get material parameters :*/
     4106        rho_ice=matpar->GetRhoIce();
     4107
     4108        /*First off, check that this segment belongs to this element: */
     4109        if ((int)*(segment+4)!=this->id)ISSMERROR("%s%i%s%i","error message: segment with id ",(int)*(segment+4)," does not belong to element with id:",this->id);
     4110
     4111        /*Recover segment node locations: */
     4112        x1=*(segment+0); y1=*(segment+1); x2=*(segment+2); y2=*(segment+3);
     4113
     4114        /*Get xyz list: */
     4115        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4116
     4117        /*get area coordinates of 0 and 1 locations: */
     4118        gauss_1=new GaussTria();
     4119        gauss_1->GaussFromCoords(x1,y1,&xyz_list[0][0]);
     4120        gauss_2=new GaussTria();
     4121        gauss_2->GaussFromCoords(x2,y2,&xyz_list[0][0]);
     4122
     4123        normal[0]=cos(atan2(x1-x2,y2-y1));
     4124        normal[1]=sin(atan2(x1-x2,y2-y1));
     4125
     4126        length=sqrt(pow(x2-x1,2.0)+pow(y2-y1,2));
     4127
     4128        Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
     4129        Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
     4130        Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
     4131
     4132        thickness_input->GetParameterValue(&h1, gauss_1);
     4133        thickness_input->GetParameterValue(&h2, gauss_2);
     4134        vx_input->GetParameterValue(&vx1,gauss_1);
     4135        vx_input->GetParameterValue(&vx2,gauss_2);
     4136        vy_input->GetParameterValue(&vy1,gauss_1);
     4137        vy_input->GetParameterValue(&vy2,gauss_2);
     4138
     4139        mass_flux= rho_ice*length*( 
     4140                                (ONETHIRD*(h1-h2)*(vx1-vx2)+0.5*h2*(vx1-vx2)+0.5*(h1-h2)*vx2+h2*vx2)*normal[0]+
     4141                                (ONETHIRD*(h1-h2)*(vy1-vy2)+0.5*h2*(vy1-vy2)+0.5*(h1-h2)*vy2+h2*vy2)*normal[1]
     4142                                );
     4143
     4144        /*Process units: */
     4145        mass_flux=UnitConversion(mass_flux,IuToExtEnum,MassFluxEnum,this->parameters);
     4146
     4147        /*clean up and return:*/
     4148        delete gauss_1;
     4149        delete gauss_2;
     4150        return mass_flux;
     4151}
     4152/*}}}*/
     4153/*FUNCTION Tria::MaxAbsVx{{{1*/
     4154void  Tria::MaxAbsVx(double* pmaxabsvx, bool process_units){
     4155
     4156        /*Get maximum:*/
     4157        double maxabsvx=this->inputs->MaxAbs(VxEnum);
     4158
     4159        /*process units if requested: */
     4160        if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum,this->parameters);
     4161
     4162        /*Assign output pointers:*/
     4163        *pmaxabsvx=maxabsvx;
     4164}
     4165/*}}}*/
     4166/*FUNCTION Tria::MaxAbsVy{{{1*/
     4167void  Tria::MaxAbsVy(double* pmaxabsvy, bool process_units){
     4168
     4169        /*Get maximum:*/
     4170        double maxabsvy=this->inputs->MaxAbs(VyEnum);
     4171
     4172        /*process units if requested: */
     4173        if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum,this->parameters);
     4174
     4175        /*Assign output pointers:*/
     4176        *pmaxabsvy=maxabsvy;
     4177}
     4178/*}}}*/
     4179/*FUNCTION Tria::MaxAbsVz{{{1*/
     4180void  Tria::MaxAbsVz(double* pmaxabsvz, bool process_units){
     4181
     4182        /*Get maximum:*/
     4183        double maxabsvz=this->inputs->MaxAbs(VzEnum);
     4184
     4185        /*process units if requested: */
     4186        if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum,this->parameters);
     4187
     4188        /*Assign output pointers:*/
     4189        *pmaxabsvz=maxabsvz;
     4190}
     4191/*}}}*/
     4192/*FUNCTION Tria::MaxVel{{{1*/
     4193void  Tria::MaxVel(double* pmaxvel, bool process_units){
     4194
     4195        /*Get maximum:*/
     4196        double maxvel=this->inputs->Max(VelEnum);
     4197
     4198        /*process units if requested: */
     4199        if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum,this->parameters);
     4200
     4201        /*Assign output pointers:*/
     4202        *pmaxvel=maxvel;
     4203}
     4204/*}}}*/
     4205/*FUNCTION Tria::MaxVx{{{1*/
     4206void  Tria::MaxVx(double* pmaxvx, bool process_units){
     4207
     4208        /*Get maximum:*/
     4209        double maxvx=this->inputs->Max(VxEnum);
     4210
     4211        /*process units if requested: */
     4212        if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum,this->parameters);
     4213
     4214        /*Assign output pointers:*/
     4215        *pmaxvx=maxvx;
     4216}
     4217/*}}}*/
     4218/*FUNCTION Tria::MaxVy{{{1*/
     4219void  Tria::MaxVy(double* pmaxvy, bool process_units){
     4220
     4221        /*Get maximum:*/
     4222        double maxvy=this->inputs->Max(VyEnum);
     4223
     4224        /*process units if requested: */
     4225        if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum,this->parameters);
     4226
     4227        /*Assign output pointers:*/
     4228        *pmaxvy=maxvy;
     4229
     4230}
     4231/*}}}*/
     4232/*FUNCTION Tria::MaxVz{{{1*/
     4233void  Tria::MaxVz(double* pmaxvz, bool process_units){
     4234
     4235        /*Get maximum:*/
     4236        double maxvz=this->inputs->Max(VzEnum);
     4237
     4238        /*process units if requested: */
     4239        if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum,this->parameters);
     4240
     4241        /*Assign output pointers:*/
     4242        *pmaxvz=maxvz;
     4243}
     4244/*}}}*/
     4245/*FUNCTION Tria::MinVel{{{1*/
     4246void  Tria::MinVel(double* pminvel, bool process_units){
     4247
     4248        /*Get minimum:*/
     4249        double minvel=this->inputs->Min(VelEnum);
     4250
     4251        /*process units if requested: */
     4252        if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum,this->parameters);
     4253
     4254        /*Assign output pointers:*/
     4255        *pminvel=minvel;
     4256}
     4257/*}}}*/
     4258/*FUNCTION Tria::MinVx{{{1*/
     4259void  Tria::MinVx(double* pminvx, bool process_units){
     4260
     4261        /*Get minimum:*/
     4262        double minvx=this->inputs->Min(VxEnum);
     4263
     4264        /*process units if requested: */
     4265        if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum,this->parameters);
     4266
     4267        /*Assign output pointers:*/
     4268        *pminvx=minvx;
     4269}
     4270/*}}}*/
     4271/*FUNCTION Tria::MinVy{{{1*/
     4272void  Tria::MinVy(double* pminvy, bool process_units){
     4273
     4274        /*Get minimum:*/
     4275        double minvy=this->inputs->Min(VyEnum);
     4276
     4277        /*process units if requested: */
     4278        if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum,this->parameters);
     4279
     4280        /*Assign output pointers:*/
     4281        *pminvy=minvy;
     4282}
     4283/*}}}*/
     4284/*FUNCTION Tria::MinVz{{{1*/
     4285void  Tria::MinVz(double* pminvz, bool process_units){
     4286
     4287        /*Get minimum:*/
     4288        double minvz=this->inputs->Min(VzEnum);
     4289
     4290        /*process units if requested: */
     4291        if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum,this->parameters);
     4292
     4293        /*Assign output pointers:*/
     4294        *pminvz=minvz;
     4295}
     4296/*}}}*/
     4297/*FUNCTION Tria::MyRank {{{1*/
     4298int    Tria::MyRank(void){
     4299        extern int my_rank;
     4300        return my_rank;
     4301}
     4302/*}}}*/
     4303/*FUNCTION Tria::PatchFill{{{1*/
     4304void  Tria::PatchFill(int* prow, Patch* patch){
     4305
     4306        int i,row;
     4307        int vertices_ids[3];
     4308
     4309        /*recover pointer: */
     4310        row=*prow;
     4311               
     4312        for(i=0;i<3;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
     4313
     4314        for(i=0;i<this->results->Size();i++){
     4315                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4316
     4317                /*For this result,fill the information in the Patch object (element id + vertices ids), and then hand
     4318                 *it to the result object, to fill the rest: */
     4319                patch->fillelementinfo(row,this->id,vertices_ids,3);
     4320                elementresult->PatchFill(row,patch);
     4321
     4322                /*increment rower: */
     4323                row++;
     4324        }
     4325
     4326        /*Assign output pointers:*/
     4327        *prow=row;
     4328}
     4329/*}}}*/
     4330/*FUNCTION Tria::PatchSize{{{1*/
     4331void  Tria::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
     4332
     4333        int     i;
     4334        int     numrows     = 0;
     4335        int     numnodes    = 0;
     4336
     4337        /*Go through all the results objects, and update the counters: */
     4338        for (i=0;i<this->results->Size();i++){
     4339                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4340                /*first, we have one more result: */
     4341                numrows++;
     4342                /*now, how many vertices and how many nodal values for this result? :*/
     4343                numnodes=elementresult->NumberOfNodalValues(); //ask result object.
     4344        }
     4345
     4346        /*Assign output pointers:*/
     4347        *pnumrows=numrows;
     4348        *pnumvertices=NUMVERTICES;
     4349        *pnumnodes=numnodes;
     4350}
     4351/*}}}*/
     4352/*FUNCTION Tria::ProcessResultsUnits{{{1*/
     4353void  Tria::ProcessResultsUnits(void){
     4354
     4355        int i;
     4356
     4357        for(i=0;i<this->results->Size();i++){
     4358                ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
     4359                elementresult->ProcessUnits(this->parameters);
     4360        }
     4361}
     4362/*}}}*/
    8384363/*FUNCTION Tria::RegularizeInversion {{{1*/
    8394364double Tria::RegularizeInversion(){
     
    9084433}
    9094434/*}}}*/
    910 /*FUNCTION Tria::CreateKMatrix {{{1*/
    911 void  Tria::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
    912 
    913         /*retreive parameters: */
    914         ElementMatrix* Ke=NULL;
    915         int analysis_type;
    916         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    917 
    918         /*Checks in debugging mode{{{2*/
    919         ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
    920         /*}}}*/
    921 
    922         /*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
    923         switch(analysis_type){
    924                 case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
    925                         Ke=CreateKMatrixDiagnosticMacAyeal();
    926                         break;
    927                 case DiagnosticHutterAnalysisEnum:
    928                         Ke=CreateKMatrixDiagnosticHutter();
    929                         break;
    930                 case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
    931                         Ke=CreateKMatrixSlope();
    932                         break;
    933                 case PrognosticAnalysisEnum:
    934                         Ke=CreateKMatrixPrognostic();
    935                         break;
    936                 case BalancedthicknessAnalysisEnum:
    937                         Ke=CreateKMatrixBalancedthickness();
    938                         break;
    939                 case AdjointBalancedthicknessAnalysisEnum:
    940                         Ke=CreateKMatrixAdjointBalancedthickness();
    941                         break;
    942                 case BalancedvelocitiesAnalysisEnum:
    943                         Ke=CreateKMatrixBalancedvelocities();
    944                         break;
    945                 default:
    946                         ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
    947         }
    948 
    949         /*Add to global matrix*/
    950         if(Ke){
    951                 Ke->AddToGlobal(Kgg,Kff,Kfs);
    952                 delete Ke;
    953         }
    954 }
    955 /*}}}*/
    956 /*FUNCTION Tria::CreatePVector {{{1*/
    957 void  Tria::CreatePVector(Vec pg, Vec pf){
    958 
    959         /*retrive parameters: */
    960         ElementVector* pe=NULL;
    961         int analysis_type;
    962         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    963 
    964         /*asserts: {{{*/
    965         /*if debugging mode, check that all pointers exist*/
    966         ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
    967         /*}}}*/
    968 
    969         /*Just branch to the correct load generator, according to the type of analysis we are carrying out: */
    970         switch(analysis_type){
    971                 case DiagnosticHorizAnalysisEnum:
    972                         pe=CreatePVectorDiagnosticMacAyeal();
    973                         break;
    974                 case AdjointHorizAnalysisEnum:
    975                         pe=CreatePVectorAdjointHoriz();
    976                         break;
    977                 case DiagnosticHutterAnalysisEnum:
    978                         pe=CreatePVectorDiagnosticHutter();
    979                         break;
    980                 case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
    981                         pe=CreatePVectorSlope();
    982                         break;
    983                 case PrognosticAnalysisEnum:
    984                         pe=CreatePVectorPrognostic();
    985                         break;
    986                 case BalancedthicknessAnalysisEnum:
    987                         pe=CreatePVectorBalancedthickness();
    988                         break;
    989                 case AdjointBalancedthicknessAnalysisEnum:
    990                         pe=CreatePVectorAdjointBalancedthickness();
    991                         break;
    992                 case BalancedvelocitiesAnalysisEnum:
    993                         pe=CreatePVectorBalancedvelocities();
    994                         break;
    995                 default:
    996                         ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
    997         }
    998 
    999         /*Add to global Vector*/
    1000         if(pe){
    1001                 pe->AddToGlobal(pg,pf);
    1002                 delete pe;
    1003         }
    1004 }
    1005 /*}}}*/
    1006 /*FUNCTION Tria::DeleteResults {{{1*/
    1007 void  Tria::DeleteResults(void){
    1008 
    1009         /*Delete and reinitialize results*/
    1010         delete this->results;
    1011         this->results=new Results();
    1012 
    1013 }
    1014 /*}}}*/
    1015 /*FUNCTION Tria::GetNodeIndex {{{1*/
    1016 int Tria::GetNodeIndex(Node* node){
    1017 
    1018         ISSMASSERT(nodes);
    1019         for(int i=0;i<NUMVERTICES;i++){
    1020                 if(node==nodes[i])
    1021                  return i;
    1022         }
    1023         ISSMERROR("Node provided not found among element nodes");
    1024 }
    1025 /*}}}*/
    1026 /*FUNCTION Tria::IsOnBed {{{1*/
    1027 bool Tria::IsOnBed(){
     4435/*FUNCTION Tria::SetClone {{{1*/
     4436void  Tria::SetClone(int* minranks){
     4437
     4438        ISSMERROR("not implemented yet");
     4439}
     4440/*}}}1*/
     4441/*FUNCTION Tria::SetCurrentConfiguration {{{1*/
     4442void  Tria::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
    10284443       
    1029         bool onbed;
    1030         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    1031         return onbed;
    1032 }
    1033 /*}}}*/
    1034 /*FUNCTION Tria::IsOnShelf {{{1*/
    1035 bool   Tria::IsOnShelf(){
    1036 
    1037         bool shelf;
    1038         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    1039         return shelf;
    1040 }
    1041 /*}}}*/
    1042 /*FUNCTION Tria::IsOnWater {{{1*/
    1043 bool   Tria::IsOnWater(){
    1044 
    1045         bool water;
    1046         inputs->GetParameterValue(&water,ElementOnWaterEnum);
    1047         return water;
    1048 }
    1049 /*}}}*/
    1050 /*FUNCTION Tria::GetSolutionFromInputs{{{1*/
    1051 void  Tria::GetSolutionFromInputs(Vec solution){
    1052 
    1053         /*retrive parameters: */
    1054         int analysis_type;
    1055         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    1056        
    1057         /*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
    1058         if (analysis_type==DiagnosticHorizAnalysisEnum)
    1059          GetSolutionFromInputsDiagnosticHoriz(solution);
    1060         else if (analysis_type==DiagnosticHutterAnalysisEnum)
    1061          GetSolutionFromInputsDiagnosticHutter(solution);
    1062         else
    1063          ISSMERROR("analysis: %s not supported yet",EnumToString(analysis_type));
    1064 
    1065 }
    1066 /*}}}*/
    1067 /*FUNCTION Tria::GetVectorFromInputs{{{1*/
    1068 void  Tria::GetVectorFromInputs(Vec vector,int NameEnum){
    1069 
    1070         int doflist1[NUMVERTICES];
    1071 
    1072         /*Find NameEnum input in the inputs dataset, and get it to fill in the vector: */
    1073         for(int i=0;i<this->inputs->Size();i++){
    1074                 Input* input=(Input*)this->inputs->GetObjectByOffset(i);
    1075                 if(input->EnumType()==NameEnum){
    1076                         /*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
    1077                         this->GetDofList1(&doflist1[0]);
    1078                         input->GetVectorFromInputs(vector,&doflist1[0]);
    1079                         break;
    1080                 }
    1081         }
    1082 }
    1083 /*}}}*/
    1084 /*FUNCTION Tria::Gradj {{{1*/
    1085 void  Tria::Gradj(Vec gradient,int control_type){
    1086 
    1087         /*If on water, grad = 0: */
    1088         if(IsOnWater())return;
    1089 
    1090         switch(control_type){
    1091                 case DragCoefficientEnum:
    1092                         GradjDrag(gradient);
    1093                         break;
    1094                 case RheologyBbarEnum:
    1095                         GradjB(gradient);
    1096                         break;
    1097                 case DhDtEnum:
    1098                         GradjDhDt(gradient);
    1099                         break;
    1100                 case VxEnum:
    1101                         GradjVx(gradient);
    1102                         break;
    1103                 case VyEnum:
    1104                         GradjVy(gradient);
    1105                         break;
    1106                 default:
    1107                         ISSMERROR("%s%i","control type not supported yet: ",control_type);
    1108         }
    1109 }
    1110 /*}}}*/
    1111 /*FUNCTION Tria::GradjB{{{1*/
    1112 void  Tria::GradjB(Vec gradient){
    1113 
    1114         /*Intermediaries*/
    1115         int        i,ig;
    1116         int        doflist[NUMVERTICES];
    1117         double     vx,vy,lambda,mu,thickness,Jdet;
    1118         double     cm_noisedmp,viscosity_complement;
    1119         double     dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dB[NDOF2];
    1120         double     xyz_list[NUMVERTICES][3];
    1121         double     basis[3],epsilon[3];
    1122         double     dbasis[NDOF2][NUMVERTICES];
    1123         double     grad_g[NUMVERTICES];
    1124         double     grad[NUMVERTICES]={0.0};
    1125         GaussTria *gauss = NULL;
    1126 
    1127         /*retrieve some parameters: */
    1128         this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
    1129 
    1130         /* Get node coordinates and dof list: */
    1131         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1132         GetDofList1(&doflist[0]);
    1133 
    1134         /*Retrieve all inputs*/
    1135         Input* thickness_input=inputs->GetInput(ThicknessEnum);            ISSMASSERT(thickness_input);
    1136         Input* vx_input=inputs->GetInput(VxEnum);                          ISSMASSERT(vx_input);
    1137         Input* vy_input=inputs->GetInput(VyEnum);                          ISSMASSERT(vy_input);
    1138         Input* adjointx_input=inputs->GetInput(AdjointxEnum);              ISSMASSERT(adjointx_input);
    1139         Input* adjointy_input=inputs->GetInput(AdjointyEnum);              ISSMASSERT(adjointy_input);
    1140         Input* rheologyb_input=matice->inputs->GetInput(RheologyBbarEnum); ISSMASSERT(rheologyb_input);
    1141 
    1142         /* Start  looping on the number of gaussian points: */
    1143         gauss=new GaussTria(4);
    1144         for (ig=gauss->begin();ig<gauss->end();ig++){
    1145 
    1146                 gauss->GaussPoint(ig);
    1147 
    1148                 thickness_input->GetParameterValue(&thickness,gauss);
    1149                 rheologyb_input->GetParameterDerivativeValue(&dB[0],&xyz_list[0][0],gauss);
    1150                 vx_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
    1151                 vy_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
    1152                 adjointx_input->GetParameterDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
    1153                 adjointy_input->GetParameterDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
    1154 
    1155                 this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
    1156                 matice->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
    1157 
    1158                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    1159                 GetNodalFunctions(basis,gauss);
    1160                 GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
    1161 
    1162                 /*standard gradient dJ/dki*/
    1163                 for (i=0;i<NUMVERTICES;i++){
    1164                         grad_g[i]=-viscosity_complement*thickness*( (2*dvx[0]+dvy[1])*2*dadjx[0]+(dvx[1]+dvy[0])*(dadjx[1]+dadjy[0])+(2*dvy[1]+dvx[0])*2*dadjy[1])*Jdet*gauss->weight*basis[i];
    1165                 }
    1166                 /*Add regularization term*/
    1167                 for (i=0;i<NUMVERTICES;i++) grad_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dB[0]+dbasis[1][i]*dB[1]);
    1168                 for(i=0;i<NUMVERTICES;i++) grad[i]+=grad_g[i];
    1169         }
    1170 
    1171         VecSetValues(gradient,NUMVERTICES,doflist,(const double*)grad,ADD_VALUES);
    1172 
    1173         /*clean-up*/
    1174         delete gauss;
    1175 }
    1176 /*}}}*/
    1177 /*FUNCTION Tria::GradjDrag {{{1*/
    1178 void  Tria::GradjDrag(Vec gradient){
    1179 
    1180         int        i,ig;
    1181         int        drag_type,analysis_type;
    1182         int        doflist1[NUMVERTICES];
    1183         double     vx,vy,lambda,mu,alpha_complement,Jdet;
    1184         double     bed,thickness,Neff,drag,cm_noisedmp;
    1185         double     xyz_list[NUMVERTICES][3];
    1186         double     dh1dh3[NDOF2][NUMVERTICES];
    1187         double     dk[NDOF2];
    1188         double     grade_g[NUMVERTICES]={0.0};
    1189         double     grade_g_gaussian[NUMVERTICES];
    1190         double     l1l2l3[3];
    1191         double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
    1192         Friction*  friction=NULL;
    1193         GaussTria  *gauss=NULL;
    1194 
    1195         /*retrive parameters: */
    1196         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    1197 
    1198         /*retrieve some parameters ands return if iceshelf: */
    1199         this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
    1200         if(IsOnShelf())return;
    1201         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1202         GetDofList1(&doflist1[0]);
    1203 
    1204         /*Build frictoin element, needed later: */
    1205         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    1206         friction=new Friction("2d",inputs,matpar,analysis_type);
    1207 
    1208         /*Retrieve all inputs we will be needing: */
    1209         Input* adjointx_input=inputs->GetInput(AdjointxEnum);               ISSMASSERT(adjointx_input);
    1210         Input* adjointy_input=inputs->GetInput(AdjointyEnum);               ISSMASSERT(adjointy_input);
    1211         Input* vx_input=inputs->GetInput(VxEnum);                           ISSMASSERT(vx_input);
    1212         Input* vy_input=inputs->GetInput(VyEnum);                           ISSMASSERT(vy_input);
    1213         Input* dragcoefficient_input=inputs->GetInput(DragCoefficientEnum); ISSMASSERT(dragcoefficient_input);
    1214 
    1215         /* Start  looping on the number of gaussian points: */
    1216         gauss=new GaussTria(4);
    1217         for (ig=gauss->begin();ig<gauss->end();ig++){
    1218 
    1219                 gauss->GaussPoint(ig);
    1220 
    1221                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    1222                 GetNodalFunctions(l1l2l3, gauss);
    1223                 GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
    1224 
    1225                 /*Build alpha_complement_list: */
    1226                 if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
    1227                 else alpha_complement=0;
    1228        
    1229                 dragcoefficient_input->GetParameterValue(&drag, gauss);
    1230                 adjointx_input->GetParameterValue(&lambda, gauss);
    1231                 adjointy_input->GetParameterValue(&mu, gauss);
    1232                 vx_input->GetParameterValue(&vx,gauss);
    1233                 vy_input->GetParameterValue(&vy,gauss);
    1234                 dragcoefficient_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
    1235 
    1236                 /*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
    1237                 for (i=0;i<NUMVERTICES;i++){
    1238 
    1239                         //standard term dJ/dki
    1240                         grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*l1l2l3[i];
    1241 
    1242                         //noise dampening d/dki(1/2*(dk/dx)^2)
    1243                         grade_g_gaussian[i]+=-cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
    1244                 }
    1245                
    1246                 /*Add gradje_g_gaussian vector to gradje_g: */
    1247                 for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
    1248         }
    1249 
    1250         VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
    1251 
    1252         /*Clean up and return*/
    1253         delete gauss;
    1254         delete friction;
    1255 }
    1256 /*}}}*/
    1257 /*FUNCTION Tria::GradjDhDt{{{1*/
    1258 void  Tria::GradjDhDt(Vec gradient){
    1259 
    1260         /*Intermediaries*/
    1261         int    doflist1[NUMVERTICES];
    1262         double lambda[NUMVERTICES];
    1263         double gradient_g[NUMVERTICES];
    1264 
    1265         GetDofList1(&doflist1[0]);
    1266 
    1267         /*Compute Gradient*/
    1268         GetParameterListOnVertices(&lambda[0],AdjointEnum);
    1269         for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
    1270 
    1271         VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)gradient_g,INSERT_VALUES);
    1272 }
    1273 /*}}}*/
    1274 /*FUNCTION Tria::GradjVx{{{1*/
    1275 void  Tria::GradjVx(Vec gradient){
    1276 
    1277         /*Intermediaries*/
    1278         int        i,ig;
    1279         int        doflist1[NUMVERTICES];
    1280         double     thickness,Jdet,cm_noisedmp;
    1281         double     l1l2l3[3];
    1282         double     dbasis[NDOF2][NUMVERTICES];
    1283         double     Dlambda[2],dp[2];
    1284         double     xyz_list[NUMVERTICES][3];
    1285         double     grade_g[NUMVERTICES] = {0.0};
    1286         GaussTria *gauss                = NULL;
    1287 
    1288         /* Get node coordinates and dof list: */
    1289         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1290         GetDofList1(&doflist1[0]);
    1291 
    1292         /*Retrieve all inputs we will be needing: */
    1293         this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
    1294         Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
    1295         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    1296 
    1297         /* Start  looping on the number of gaussian points: */
    1298         gauss=new GaussTria(2);
    1299         for (ig=gauss->begin();ig<gauss->end();ig++){
    1300 
    1301                 gauss->GaussPoint(ig);
    1302 
    1303                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    1304                 GetNodalFunctions(l1l2l3, gauss);
    1305                 GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
    1306                
    1307                 adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
    1308                 thickness_input->GetParameterValue(&thickness, gauss);
    1309                 thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
    1310 
    1311                 for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[0]*Jdet*gauss->weight*l1l2l3[i];
    1312 
    1313                 //noise dampening d/dki(1/2*(dk/dx)^2)
    1314                 //for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
    1315         }
    1316 
    1317         VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
    1318 
    1319         /*Clean up and return*/
    1320         delete gauss;
    1321 }
    1322 /*}}}*/
    1323 /*FUNCTION Tria::GradjVy{{{1*/
    1324 void  Tria::GradjVy(Vec gradient){
    1325 
    1326         /*Intermediaries*/
    1327         int        i,ig;
    1328         int        doflist1[NUMVERTICES];
    1329         double     thickness,Jdet,cm_noisedmp;
    1330         double     l1l2l3[3];
    1331         double     dbasis[NDOF2][NUMVERTICES];
    1332         double     Dlambda[2],dp[2];
    1333         double     xyz_list[NUMVERTICES][3];
    1334         double     grade_g[NUMVERTICES] = {0.0};
    1335         GaussTria *gauss                = NULL;
    1336 
    1337         /* Get node coordinates and dof list: */
    1338         this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
    1339         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1340         GetDofList1(&doflist1[0]);
    1341 
    1342         /*Retrieve all inputs we will be needing: */
    1343         Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
    1344         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    1345 
    1346         /* Start  looping on the number of gaussian points: */
    1347         gauss=new GaussTria(2);
    1348         for (ig=gauss->begin();ig<gauss->end();ig++){
    1349 
    1350                 gauss->GaussPoint(ig);
    1351 
    1352                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    1353                 GetNodalFunctions(l1l2l3, gauss);
    1354                 GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
    1355 
    1356                 adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
    1357                 thickness_input->GetParameterValue(&thickness, gauss);
    1358                 thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
    1359 
    1360                 for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[1]*Jdet*gauss->weight*l1l2l3[i];
    1361 
    1362                 //noise dampening d/dki(1/2*(dk/dx)^2)
    1363                 //for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
    1364         }
    1365 
    1366         VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
    1367 
    1368         /*Clean up and return*/
    1369         delete gauss;
    1370 }
    1371 /*}}}*/
    1372 /*FUNCTION Tria::InputControlUpdate{{{1*/
    1373 void  Tria::InputControlUpdate(double scalar,bool save_parameter){
    1374 
    1375         /*Intermediary*/
    1376         int    num_controls;
    1377         int*   control_type=NULL;
    1378         Input* input=NULL;
    1379         double *cm_min=NULL;
    1380         double *cm_max=NULL;
    1381 
    1382         /*retrieve some parameters: */
    1383         this->parameters->FindParam(&cm_min,NULL,CmMinEnum);
    1384         this->parameters->FindParam(&cm_max,NULL,CmMaxEnum);
    1385         this->parameters->FindParam(&num_controls,NumControlsEnum);
    1386         this->parameters->FindParam(&control_type,NULL,ControlTypeEnum);
    1387 
    1388         for(int i=0;i<num_controls;i++){
    1389 
    1390                 if(control_type[i]==RheologyBbarEnum){
    1391                         input=(Input*)matice->inputs->GetInput(control_type[i]); ISSMASSERT(input);
    1392                 }
    1393                 else{
    1394                         input=(Input*)this->inputs->GetInput(control_type[i]);   ISSMASSERT(input);
    1395                 }
    1396 
    1397                 if (input->Enum()!=ControlInputEnum){
    1398                         ISSMERROR("input %s is not a ControlInput",EnumToString(control_type[i]));
    1399                 }
    1400 
    1401                 ((ControlInput*)input)->UpdateValue(scalar);
    1402                 input->Constrain(cm_min[i],cm_max[i]);
    1403                 if (save_parameter) ((ControlInput*)input)->SaveValue();
    1404 
    1405         }
    1406 
    1407         /*Clean up and return*/
    1408         xfree((void**)&control_type);
    1409         xfree((void**)&cm_min);
    1410         xfree((void**)&cm_max);
    1411 }
    1412 /*}}}*/
    1413 /*FUNCTION Tria::InputConvergence{{{1*/
    1414 bool Tria::InputConvergence(double* eps, int* enums,int num_enums,int* criterionenums,double* criterionvalues,int num_criterionenums){
    1415 
    1416         bool    converged=true;
    1417         int     i;
    1418         Input** new_inputs=NULL;
    1419         Input** old_inputs=NULL;
    1420 
    1421         new_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the new inputs
    1422         old_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the old inputs
    1423 
    1424         for(i=0;i<num_enums/2;i++){
    1425                 new_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+0]);
    1426                 old_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+1]);
    1427                 if(!new_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
    1428                 if(!old_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
    1429         }
    1430 
    1431         /*ok, we've got the inputs (new and old), now loop throught the number of criterions and fill the eps array:*/
    1432         for(i=0;i<num_criterionenums;i++){
    1433                 IsInputConverged(eps+i,new_inputs,old_inputs,num_enums/2,criterionenums[i]);
    1434                 if(eps[i]>criterionvalues[i]) converged=false;
    1435         }
    1436 
    1437         /*clean up and return*/
    1438         xfree((void**)&new_inputs);
    1439         xfree((void**)&old_inputs);
    1440         return converged;
    1441 }
    1442 /*}}}*/
    1443 /*FUNCTION Tria::InputDepthAverageAtBase {{{1*/
    1444 void  Tria::InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum){
    1445 
    1446         /*New input*/
    1447         Input* oldinput=NULL;
    1448         Input* newinput=NULL;
    1449 
    1450         /*copy input of enum_type*/
    1451         if (object_enum==ElementsEnum)
    1452          oldinput=(Input*)this->inputs->GetInput(enum_type);
    1453         else if (object_enum==MaterialsEnum)
    1454          oldinput=(Input*)this->matice->inputs->GetInput(enum_type);
    1455         else
    1456          ISSMERROR("object %s not supported yet",EnumToString(object_enum));
    1457         if(!oldinput)ISSMERROR("%s%s"," could not find old input with enum: ",EnumToString(enum_type));
    1458         newinput=(Input*)oldinput->copy();
    1459 
    1460         /*Assign new name (average)*/
    1461         newinput->ChangeEnum(average_enum_type);
    1462 
    1463         /*Add new input to current element*/
    1464         if (object_enum==ElementsEnum)
    1465          this->inputs->AddInput((Input*)newinput);
    1466         else if (object_enum==MaterialsEnum)
    1467          this->matice->inputs->AddInput((Input*)newinput);
    1468         else
    1469          ISSMERROR("object %s not supported yet",EnumToString(object_enum));
    1470 }
    1471 /*}}}*/
    1472 /*FUNCTION Tria::InputDuplicate{{{1*/
    1473 void  Tria::InputDuplicate(int original_enum,int new_enum){
    1474 
    1475         /*Call inputs method*/
    1476         if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
    1477 
    1478 }
    1479 /*}}}*/
    1480 /*FUNCTION Tria::InputScale{{{1*/
    1481 void  Tria::InputScale(int enum_type,double scale_factor){
    1482 
    1483         Input* input=NULL;
    1484 
    1485         /*Make a copy of the original input: */
    1486         input=(Input*)this->inputs->GetInput(enum_type);
    1487         if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
    1488 
    1489         /*Scale: */
    1490         input->Scale(scale_factor);
    1491 }
    1492 /*}}}*/
    1493 /*FUNCTION Tria::InputArtificialNoise{{{1*/
    1494 void  Tria::InputArtificialNoise(int enum_type,double min,double max){
    1495 
    1496         Input* input=NULL;
    1497 
    1498         /*Make a copy of the original input: */
    1499         input=(Input*)this->inputs->GetInput(enum_type);
    1500         if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
    1501 
    1502         /*ArtificialNoise: */
    1503         input->ArtificialNoise(min,max);
    1504 }
    1505 /*}}}*/
    1506 /*FUNCTION Tria::InputToResult{{{1*/
    1507 void  Tria::InputToResult(int enum_type,int step,double time){
    1508 
    1509         int    i;
    1510         Input *input = NULL;
    1511 
    1512         /*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
    1513         if (enum_type==RheologyBbarEnum) input=this->matice->inputs->GetInput(enum_type);
    1514         else input=this->inputs->GetInput(enum_type);
    1515         if (!input) ISSMERROR("Input %s not found in tria->inputs",EnumToString(enum_type));
    1516 
    1517         /*If we don't find it, no big deal, just don't do the transfer. Otherwise, build a new Result
    1518          * object out of the input, with the additional step and time information: */
    1519         this->results->AddObject((Object*)input->SpawnResult(step,time));
    1520         if(input->Enum()==ControlInputEnum) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
    1521 }
    1522 /*}}}*/
    1523 /*FUNCTION Tria::MassFlux {{{1*/
    1524 double Tria::MassFlux( double* segment,bool process_units){
    1525 
    1526         const int    numdofs=2;
    1527 
    1528         int        i;
    1529         double     mass_flux=0;
    1530         double     xyz_list[NUMVERTICES][3];
    1531         double     normal[2];
    1532         double     length,rho_ice;
    1533         double     x1,y1,x2,y2,h1,h2;
    1534         double     vx1,vx2,vy1,vy2;
    1535         GaussTria* gauss_1=NULL;
    1536         GaussTria* gauss_2=NULL;
    1537 
    1538         /*Get material parameters :*/
    1539         rho_ice=matpar->GetRhoIce();
    1540 
    1541         /*First off, check that this segment belongs to this element: */
    1542         if ((int)*(segment+4)!=this->id)ISSMERROR("%s%i%s%i","error message: segment with id ",(int)*(segment+4)," does not belong to element with id:",this->id);
    1543 
    1544         /*Recover segment node locations: */
    1545         x1=*(segment+0); y1=*(segment+1); x2=*(segment+2); y2=*(segment+3);
    1546 
    1547         /*Get xyz list: */
    1548         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1549 
    1550         /*get area coordinates of 0 and 1 locations: */
    1551         gauss_1=new GaussTria();
    1552         gauss_1->GaussFromCoords(x1,y1,&xyz_list[0][0]);
    1553         gauss_2=new GaussTria();
    1554         gauss_2->GaussFromCoords(x2,y2,&xyz_list[0][0]);
    1555 
    1556         normal[0]=cos(atan2(x1-x2,y2-y1));
    1557         normal[1]=sin(atan2(x1-x2,y2-y1));
    1558 
    1559         length=sqrt(pow(x2-x1,2.0)+pow(y2-y1,2));
    1560 
    1561         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    1562         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    1563         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    1564 
    1565         thickness_input->GetParameterValue(&h1, gauss_1);
    1566         thickness_input->GetParameterValue(&h2, gauss_2);
    1567         vx_input->GetParameterValue(&vx1,gauss_1);
    1568         vx_input->GetParameterValue(&vx2,gauss_2);
    1569         vy_input->GetParameterValue(&vy1,gauss_1);
    1570         vy_input->GetParameterValue(&vy2,gauss_2);
    1571 
    1572         mass_flux= rho_ice*length*( 
    1573                                 (ONETHIRD*(h1-h2)*(vx1-vx2)+0.5*h2*(vx1-vx2)+0.5*(h1-h2)*vx2+h2*vx2)*normal[0]+
    1574                                 (ONETHIRD*(h1-h2)*(vy1-vy2)+0.5*h2*(vy1-vy2)+0.5*(h1-h2)*vy2+h2*vy2)*normal[1]
    1575                                 );
    1576 
    1577         /*Process units: */
    1578         mass_flux=UnitConversion(mass_flux,IuToExtEnum,MassFluxEnum,this->parameters);
    1579 
    1580         /*clean up and return:*/
    1581         delete gauss_1;
    1582         delete gauss_2;
    1583         return mass_flux;
    1584 }
    1585 /*}}}*/
    1586 /*FUNCTION Tria::MaxAbsVx{{{1*/
    1587 void  Tria::MaxAbsVx(double* pmaxabsvx, bool process_units){
    1588 
    1589         /*Get maximum:*/
    1590         double maxabsvx=this->inputs->MaxAbs(VxEnum);
    1591 
    1592         /*process units if requested: */
    1593         if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum,this->parameters);
    1594 
    1595         /*Assign output pointers:*/
    1596         *pmaxabsvx=maxabsvx;
    1597 }
    1598 /*}}}*/
    1599 /*FUNCTION Tria::MaxAbsVy{{{1*/
    1600 void  Tria::MaxAbsVy(double* pmaxabsvy, bool process_units){
    1601 
    1602         /*Get maximum:*/
    1603         double maxabsvy=this->inputs->MaxAbs(VyEnum);
    1604 
    1605         /*process units if requested: */
    1606         if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum,this->parameters);
    1607 
    1608         /*Assign output pointers:*/
    1609         *pmaxabsvy=maxabsvy;
    1610 }
    1611 /*}}}*/
    1612 /*FUNCTION Tria::MaxAbsVz{{{1*/
    1613 void  Tria::MaxAbsVz(double* pmaxabsvz, bool process_units){
    1614 
    1615         /*Get maximum:*/
    1616         double maxabsvz=this->inputs->MaxAbs(VzEnum);
    1617 
    1618         /*process units if requested: */
    1619         if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum,this->parameters);
    1620 
    1621         /*Assign output pointers:*/
    1622         *pmaxabsvz=maxabsvz;
    1623 }
    1624 /*}}}*/
    1625 /*FUNCTION Tria::MaxVel{{{1*/
    1626 void  Tria::MaxVel(double* pmaxvel, bool process_units){
    1627 
    1628         /*Get maximum:*/
    1629         double maxvel=this->inputs->Max(VelEnum);
    1630 
    1631         /*process units if requested: */
    1632         if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum,this->parameters);
    1633 
    1634         /*Assign output pointers:*/
    1635         *pmaxvel=maxvel;
    1636 }
    1637 /*}}}*/
    1638 /*FUNCTION Tria::MaxVx{{{1*/
    1639 void  Tria::MaxVx(double* pmaxvx, bool process_units){
    1640 
    1641         /*Get maximum:*/
    1642         double maxvx=this->inputs->Max(VxEnum);
    1643 
    1644         /*process units if requested: */
    1645         if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum,this->parameters);
    1646 
    1647         /*Assign output pointers:*/
    1648         *pmaxvx=maxvx;
    1649 }
    1650 /*}}}*/
    1651 /*FUNCTION Tria::MaxVy{{{1*/
    1652 void  Tria::MaxVy(double* pmaxvy, bool process_units){
    1653 
    1654         /*Get maximum:*/
    1655         double maxvy=this->inputs->Max(VyEnum);
    1656 
    1657         /*process units if requested: */
    1658         if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum,this->parameters);
    1659 
    1660         /*Assign output pointers:*/
    1661         *pmaxvy=maxvy;
    1662 
    1663 }
    1664 /*}}}*/
    1665 /*FUNCTION Tria::MaxVz{{{1*/
    1666 void  Tria::MaxVz(double* pmaxvz, bool process_units){
    1667 
    1668         /*Get maximum:*/
    1669         double maxvz=this->inputs->Max(VzEnum);
    1670 
    1671         /*process units if requested: */
    1672         if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum,this->parameters);
    1673 
    1674         /*Assign output pointers:*/
    1675         *pmaxvz=maxvz;
    1676 }
    1677 /*}}}*/
    1678 /*FUNCTION Tria::MinVel{{{1*/
    1679 void  Tria::MinVel(double* pminvel, bool process_units){
    1680 
    1681         /*Get minimum:*/
    1682         double minvel=this->inputs->Min(VelEnum);
    1683 
    1684         /*process units if requested: */
    1685         if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum,this->parameters);
    1686 
    1687         /*Assign output pointers:*/
    1688         *pminvel=minvel;
    1689 }
    1690 /*}}}*/
    1691 /*FUNCTION Tria::MinVx{{{1*/
    1692 void  Tria::MinVx(double* pminvx, bool process_units){
    1693 
    1694         /*Get minimum:*/
    1695         double minvx=this->inputs->Min(VxEnum);
    1696 
    1697         /*process units if requested: */
    1698         if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum,this->parameters);
    1699 
    1700         /*Assign output pointers:*/
    1701         *pminvx=minvx;
    1702 }
    1703 /*}}}*/
    1704 /*FUNCTION Tria::MinVy{{{1*/
    1705 void  Tria::MinVy(double* pminvy, bool process_units){
    1706 
    1707         /*Get minimum:*/
    1708         double minvy=this->inputs->Min(VyEnum);
    1709 
    1710         /*process units if requested: */
    1711         if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum,this->parameters);
    1712 
    1713         /*Assign output pointers:*/
    1714         *pminvy=minvy;
    1715 }
    1716 /*}}}*/
    1717 /*FUNCTION Tria::MinVz{{{1*/
    1718 void  Tria::MinVz(double* pminvz, bool process_units){
    1719 
    1720         /*Get minimum:*/
    1721         double minvz=this->inputs->Min(VzEnum);
    1722 
    1723         /*process units if requested: */
    1724         if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum,this->parameters);
    1725 
    1726         /*Assign output pointers:*/
    1727         *pminvz=minvz;
    1728 }
    1729 /*}}}*/
    1730 /*FUNCTION Tria::TimeAdapt{{{1*/
    1731 double  Tria::TimeAdapt(void){
    1732 
    1733         /*intermediary: */
    1734         int    i;
    1735         double C,dt;
    1736         double dx,dy;
    1737         double maxx,minx;
    1738         double maxy,miny;
    1739         double maxabsvx,maxabsvy;
    1740         double xyz_list[NUMVERTICES][3];
    1741 
    1742         /*get CFL coefficient:*/
    1743         this->parameters->FindParam(&C,CflCoefficientEnum);
    1744 
    1745         /*Get for Vx and Vy, the max of abs value: */
    1746         this->MaxAbsVx(&maxabsvx,false);
    1747         this->MaxAbsVy(&maxabsvy,false);
    1748 
    1749         /* Get node coordinates and dof list: */
    1750         GetVerticesCoordinates(&xyz_list[0][0], this->nodes, NUMVERTICES);
    1751 
    1752         minx=xyz_list[0][0];
    1753         maxx=xyz_list[0][0];
    1754         miny=xyz_list[0][1];
    1755         maxy=xyz_list[0][1];
    1756        
    1757         for(i=1;i<NUMVERTICES;i++){
    1758                 if (xyz_list[i][0]<minx)minx=xyz_list[i][0];
    1759                 if (xyz_list[i][0]>maxx)maxx=xyz_list[i][0];
    1760                 if (xyz_list[i][1]<miny)miny=xyz_list[i][1];
    1761                 if (xyz_list[i][1]>maxy)maxy=xyz_list[i][1];
    1762         }
    1763         dx=maxx-minx;
    1764         dy=maxy-miny;
    1765 
    1766         /*CFL criterion: */
    1767         dt=C/(maxabsvy/dx+maxabsvy/dy);
    1768 
    1769         return dt;
    1770 }
    1771 /*}}}*/
    1772 /*FUNCTION Tria::ThicknessAbsMisfit {{{1*/
    1773 double Tria::ThicknessAbsMisfit(bool process_units){
    1774 
    1775         /* Constants */
    1776         const int    numdof=1*NUMVERTICES;
    1777 
    1778         /*Intermediaries*/
    1779         int        i,ig;
    1780         double     thickness,thicknessobs,weight;
    1781         double     Jdet;
    1782         double     Jelem = 0;
    1783         double     xyz_list[NUMVERTICES][3];
    1784         GaussTria *gauss = NULL;
    1785 
    1786         /*If on water, return 0: */
    1787         if(IsOnWater())return 0;
    1788 
    1789         /* Get node coordinates and dof list: */
    1790         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    1791 
    1792         /*Retrieve all inputs we will be needing: */
    1793         Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
    1794         Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
    1795         Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
    1796 
    1797         /* Start  looping on the number of gaussian points: */
    1798         gauss=new GaussTria(2);
    1799         for (ig=gauss->begin();ig<gauss->end();ig++){
    1800 
    1801                 gauss->GaussPoint(ig);
    1802 
    1803                 /* Get Jacobian determinant: */
    1804                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    1805 
    1806                 /*Get parameters at gauss point*/
    1807                 thickness_input->GetParameterValue(&thickness,gauss);
    1808                 thicknessobs_input->GetParameterValue(&thicknessobs,gauss);
    1809                 weights_input->GetParameterValue(&weight,gauss);
    1810 
    1811                 /*compute ThicknessAbsMisfit*/
    1812                 Jelem+=0.5*pow(thickness-thicknessobs,2.0)*weight*Jdet*gauss->weight;
    1813         }
    1814 
    1815         /* clean up and Return: */
    1816         delete gauss;
    1817         return Jelem;
     4444        /*go into parameters and get the analysis_counter: */
     4445        int analysis_counter;
     4446        parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
     4447
     4448        /*Get Element type*/
     4449        this->element_type=this->element_type_list[analysis_counter];
     4450
     4451        /*Pick up nodes*/
     4452        if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
     4453        else this->nodes=NULL;
     4454
    18184455}
    18194456/*}}}*/
     
    18964533}
    18974534/*}}}*/
    1898 /*FUNCTION Tria::SurfaceRelVelMisfit {{{1*/
    1899 double Tria::SurfaceRelVelMisfit(bool process_units){
     4535/*FUNCTION Tria::SurfaceArea {{{1*/
     4536double Tria::SurfaceArea(void){
     4537
     4538        int    i;
     4539        double S;
     4540        double normal[3];
     4541        double v13[3],v23[3];
     4542        double xyz_list[NUMVERTICES][3];
     4543
     4544        /*If on water, return 0: */
     4545        if(IsOnWater())return 0;
     4546
     4547        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
     4548
     4549        for (i=0;i<3;i++){
     4550                v13[i]=xyz_list[0][i]-xyz_list[2][i];
     4551                v23[i]=xyz_list[1][i]-xyz_list[2][i];
     4552        }
     4553
     4554        normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
     4555        normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
     4556        normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
     4557
     4558        S = 0.5 * sqrt(pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2));
     4559
     4560        /*Return: */
     4561        return S;
     4562}
     4563/*}}}*/
     4564/*FUNCTION Tria::SurfaceAverageVelMisfit {{{1*/
     4565double Tria::SurfaceAverageVelMisfit(bool process_units){
    19004566
    19014567        const int    numdof=2*NUMVERTICES;
    19024568
    19034569        int        i,ig;
    1904         double     Jelem=0;
    1905         double     scalex=1,scaley=1;
    1906         double     meanvel, epsvel,misfit,Jdet;
    1907         double     velocity_mag,obs_velocity_mag;
     4570        int        fit=-1;
     4571        double     Jelem=0,S=0;
     4572        double     scalex=1, scaley=1;
     4573        double     meanvel, epsvel,Jdet;
     4574        double     velocity_mag,obs_velocity_mag,misfit;
    19084575        double     xyz_list[NUMVERTICES][3];
    19094576        double     vx_list[NUMVERTICES];
     
    19234590
    19244591        /* Recover input data: */
     4592        inputs->GetParameterValue(&S,SurfaceAreaEnum);
    19254593        GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
    19264594        GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
     
    19334601        this->parameters->FindParam(&epsvel,EpsVelEnum);
    19344602
    1935         /* Compute SurfaceRelVelMisfit at the 3 nodes
     4603        /* Compute SurfaceAverageVelMisfit at the 3 nodes
    19364604         * Here we integrate linearized functions:
    19374605         *               
     
    19434611         */
    19444612
    1945         /*We are using a relative misfit:
    1946          *                       
    1947          *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
    1948          * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
    1949          *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
    1950          *              obs                        obs                     
     4613        /*We are using a spacially average absolute misfit:
     4614         *
     4615         *      1                    2              2
     4616         * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
     4617         *      S                obs            obs
    19514618         */
    1952         for (i=0;i<NUMVERTICES;i++){
    1953                 scalex=pow(meanvel/(obs_vx_list[i]+epsvel),(double)2);
    1954                 scaley=pow(meanvel/(obs_vy_list[i]+epsvel),(double)2);
    1955                 if(obs_vx_list[i]==0)scalex=0;
    1956                 if(obs_vy_list[i]==0)scaley=0;
    1957                 misfit_list[i]=0.5*(scalex*pow((vx_list[i]-obs_vx_list[i]),2)+scaley*pow((vy_list[i]-obs_vy_list[i]),2));
    1958         }
     4619        for (i=0;i<NUMVERTICES;i++) misfit_square_list[i]=pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2);
    19594620
    19604621        /*Process units: */
    1961         if(process_units)UnitConversion(&misfit_list[0],NUMVERTICES,IuToExtEnum,SurfaceRelVelMisfitEnum,this->parameters);
     4622        if(process_units)UnitConversion(&misfit_square_list[0],NUMVERTICES,IuToExtEnum,SurfaceAverageVelMisfitEnum,this->parameters);
     4623
     4624        /*Take the square root, and scale by surface: */
     4625        for (i=0;i<NUMVERTICES;i++)misfit_list[i]=pow(misfit_square_list[i],2)/S;
    19624626
    19634627        /*Apply weights to misfits*/
     
    19754639        }
    19764640
    1977         /*clean up and Return: */
     4641        /*clean-up and Return: */
    19784642        delete gauss;
    19794643        return Jelem;
     
    21454809}
    21464810/*}}}*/
    2147 /*FUNCTION Tria::SurfaceAverageVelMisfit {{{1*/
    2148 double Tria::SurfaceAverageVelMisfit(bool process_units){
     4811/*FUNCTION Tria::SurfaceNormal{{{1*/
     4812void Tria::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
     4813
     4814        int i;
     4815        double v13[3],v23[3];
     4816        double normal[3];
     4817        double normal_norm;
     4818
     4819        for (i=0;i<3;i++){
     4820                v13[i]=xyz_list[0][i]-xyz_list[2][i];
     4821                v23[i]=xyz_list[1][i]-xyz_list[2][i];
     4822        }
     4823
     4824        normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
     4825        normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
     4826        normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
     4827
     4828        normal_norm=sqrt( pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2) );
     4829
     4830        *(surface_normal)=normal[0]/normal_norm;
     4831        *(surface_normal+1)=normal[1]/normal_norm;
     4832        *(surface_normal+2)=normal[2]/normal_norm;
     4833}
     4834/*}}}*/
     4835/*FUNCTION Tria::SurfaceRelVelMisfit {{{1*/
     4836double Tria::SurfaceRelVelMisfit(bool process_units){
    21494837
    21504838        const int    numdof=2*NUMVERTICES;
    21514839
    21524840        int        i,ig;
    2153         int        fit=-1;
    2154         double     Jelem=0,S=0;
    2155         double     scalex=1, scaley=1;
    2156         double     meanvel, epsvel,Jdet;
    2157         double     velocity_mag,obs_velocity_mag,misfit;
     4841        double     Jelem=0;
     4842        double     scalex=1,scaley=1;
     4843        double     meanvel, epsvel,misfit,Jdet;
     4844        double     velocity_mag,obs_velocity_mag;
    21584845        double     xyz_list[NUMVERTICES][3];
    21594846        double     vx_list[NUMVERTICES];
     
    21734860
    21744861        /* Recover input data: */
    2175         inputs->GetParameterValue(&S,SurfaceAreaEnum);
    21764862        GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
    21774863        GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
     
    21844870        this->parameters->FindParam(&epsvel,EpsVelEnum);
    21854871
    2186         /* Compute SurfaceAverageVelMisfit at the 3 nodes
     4872        /* Compute SurfaceRelVelMisfit at the 3 nodes
    21874873         * Here we integrate linearized functions:
    21884874         *               
     
    21944880         */
    21954881
    2196         /*We are using a spacially average absolute misfit:
    2197          *
    2198          *      1                    2              2
    2199          * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
    2200          *      S                obs            obs
     4882        /*We are using a relative misfit:
     4883         *                       
     4884         *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
     4885         * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
     4886         *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
     4887         *              obs                        obs                     
    22014888         */
    2202         for (i=0;i<NUMVERTICES;i++) misfit_square_list[i]=pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2);
     4889        for (i=0;i<NUMVERTICES;i++){
     4890                scalex=pow(meanvel/(obs_vx_list[i]+epsvel),(double)2);
     4891                scaley=pow(meanvel/(obs_vy_list[i]+epsvel),(double)2);
     4892                if(obs_vx_list[i]==0)scalex=0;
     4893                if(obs_vy_list[i]==0)scaley=0;
     4894                misfit_list[i]=0.5*(scalex*pow((vx_list[i]-obs_vx_list[i]),2)+scaley*pow((vy_list[i]-obs_vy_list[i]),2));
     4895        }
    22034896
    22044897        /*Process units: */
    2205         if(process_units)UnitConversion(&misfit_square_list[0],NUMVERTICES,IuToExtEnum,SurfaceAverageVelMisfitEnum,this->parameters);
    2206 
    2207         /*Take the square root, and scale by surface: */
    2208         for (i=0;i<NUMVERTICES;i++)misfit_list[i]=pow(misfit_square_list[i],2)/S;
     4898        if(process_units)UnitConversion(&misfit_list[0],NUMVERTICES,IuToExtEnum,SurfaceRelVelMisfitEnum,this->parameters);
    22094899
    22104900        /*Apply weights to misfits*/
     
    22224912        }
    22234913
    2224         /*clean-up and Return: */
     4914        /*clean up and Return: */
    22254915        delete gauss;
    22264916        return Jelem;
    22274917}
    22284918/*}}}*/
    2229 /*FUNCTION Tria::PatchFill{{{1*/
    2230 void  Tria::PatchFill(int* prow, Patch* patch){
    2231 
    2232         int i,row;
    2233         int vertices_ids[3];
    2234 
    2235         /*recover pointer: */
    2236         row=*prow;
    2237                
    2238         for(i=0;i<3;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
    2239 
    2240         for(i=0;i<this->results->Size();i++){
    2241                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    2242 
    2243                 /*For this result,fill the information in the Patch object (element id + vertices ids), and then hand
    2244                  *it to the result object, to fill the rest: */
    2245                 patch->fillelementinfo(row,this->id,vertices_ids,3);
    2246                 elementresult->PatchFill(row,patch);
    2247 
    2248                 /*increment rower: */
    2249                 row++;
    2250         }
    2251 
    2252         /*Assign output pointers:*/
    2253         *prow=row;
    2254 }
    2255 /*}}}*/
    2256 /*FUNCTION Tria::PatchSize{{{1*/
    2257 void  Tria::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
    2258 
    2259         int     i;
    2260         int     numrows     = 0;
    2261         int     numnodes    = 0;
    2262 
    2263         /*Go through all the results objects, and update the counters: */
    2264         for (i=0;i<this->results->Size();i++){
    2265                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    2266                 /*first, we have one more result: */
    2267                 numrows++;
    2268                 /*now, how many vertices and how many nodal values for this result? :*/
    2269                 numnodes=elementresult->NumberOfNodalValues(); //ask result object.
    2270         }
    2271 
    2272         /*Assign output pointers:*/
    2273         *pnumrows=numrows;
    2274         *pnumvertices=NUMVERTICES;
    2275         *pnumnodes=numnodes;
    2276 }
    2277 /*}}}*/
    2278 /*FUNCTION Tria::ProcessResultsUnits{{{1*/
    2279 void  Tria::ProcessResultsUnits(void){
    2280 
    2281         int i;
    2282 
    2283         for(i=0;i<this->results->Size();i++){
    2284                 ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
    2285                 elementresult->ProcessUnits(this->parameters);
    2286         }
    2287 }
    2288 /*}}}*/
    2289 /*FUNCTION Tria::SurfaceArea {{{1*/
    2290 double Tria::SurfaceArea(void){
    2291 
    2292         int    i;
    2293         double S;
    2294         double normal[3];
    2295         double v13[3],v23[3];
    2296         double xyz_list[NUMVERTICES][3];
     4919/*FUNCTION Tria::ThicknessAbsMisfit {{{1*/
     4920double Tria::ThicknessAbsMisfit(bool process_units){
     4921
     4922        /* Constants */
     4923        const int    numdof=1*NUMVERTICES;
     4924
     4925        /*Intermediaries*/
     4926        int        i,ig;
     4927        double     thickness,thicknessobs,weight;
     4928        double     Jdet;
     4929        double     Jelem = 0;
     4930        double     xyz_list[NUMVERTICES][3];
     4931        GaussTria *gauss = NULL;
    22974932
    22984933        /*If on water, return 0: */
    22994934        if(IsOnWater())return 0;
    23004935
     4936        /* Get node coordinates and dof list: */
    23014937        GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    23024938
    2303         for (i=0;i<3;i++){
    2304                 v13[i]=xyz_list[0][i]-xyz_list[2][i];
    2305                 v23[i]=xyz_list[1][i]-xyz_list[2][i];
    2306         }
    2307 
    2308         normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
    2309         normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
    2310         normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
    2311 
    2312         S = 0.5 * sqrt(pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2));
    2313 
    2314         /*Return: */
    2315         return S;
     4939        /*Retrieve all inputs we will be needing: */
     4940        Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
     4941        Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
     4942        Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
     4943
     4944        /* Start  looping on the number of gaussian points: */
     4945        gauss=new GaussTria(2);
     4946        for (ig=gauss->begin();ig<gauss->end();ig++){
     4947
     4948                gauss->GaussPoint(ig);
     4949
     4950                /* Get Jacobian determinant: */
     4951                GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
     4952
     4953                /*Get parameters at gauss point*/
     4954                thickness_input->GetParameterValue(&thickness,gauss);
     4955                thicknessobs_input->GetParameterValue(&thicknessobs,gauss);
     4956                weights_input->GetParameterValue(&weight,gauss);
     4957
     4958                /*compute ThicknessAbsMisfit*/
     4959                Jelem+=0.5*pow(thickness-thicknessobs,2.0)*weight*Jdet*gauss->weight;
     4960        }
     4961
     4962        /* clean up and Return: */
     4963        delete gauss;
     4964        return Jelem;
     4965}
     4966/*}}}*/
     4967/*FUNCTION Tria::TimeAdapt{{{1*/
     4968double  Tria::TimeAdapt(void){
     4969
     4970        /*intermediary: */
     4971        int    i;
     4972        double C,dt;
     4973        double dx,dy;
     4974        double maxx,minx;
     4975        double maxy,miny;
     4976        double maxabsvx,maxabsvy;
     4977        double xyz_list[NUMVERTICES][3];
     4978
     4979        /*get CFL coefficient:*/
     4980        this->parameters->FindParam(&C,CflCoefficientEnum);
     4981
     4982        /*Get for Vx and Vy, the max of abs value: */
     4983        this->MaxAbsVx(&maxabsvx,false);
     4984        this->MaxAbsVy(&maxabsvy,false);
     4985
     4986        /* Get node coordinates and dof list: */
     4987        GetVerticesCoordinates(&xyz_list[0][0], this->nodes, NUMVERTICES);
     4988
     4989        minx=xyz_list[0][0];
     4990        maxx=xyz_list[0][0];
     4991        miny=xyz_list[0][1];
     4992        maxy=xyz_list[0][1];
     4993
     4994        for(i=1;i<NUMVERTICES;i++){
     4995                if (xyz_list[i][0]<minx)minx=xyz_list[i][0];
     4996                if (xyz_list[i][0]>maxx)maxx=xyz_list[i][0];
     4997                if (xyz_list[i][1]<miny)miny=xyz_list[i][1];
     4998                if (xyz_list[i][1]>maxy)maxy=xyz_list[i][1];
     4999        }
     5000        dx=maxx-minx;
     5001        dy=maxy-miny;
     5002
     5003        /*CFL criterion: */
     5004        dt=C/(maxabsvy/dx+maxabsvy/dy);
     5005
     5006        return dt;
    23165007}
    23175008/*}}}*/
     
    24475138}
    24485139/*}}}*/
    2449 
    2450 /*Tria specific routines: */
    2451 /*FUNCTION Tria::CreateKMatrixAdjointBalancedthickness {{{1*/
    2452 ElementMatrix* Tria::CreateKMatrixAdjointBalancedthickness(void){
    2453 
    2454         ElementMatrix* Ke=NULL;
    2455 
    2456         /*Get Element Matrix of the forward model*/
    2457         switch(GetElementType()){
    2458                 case P1Enum:
    2459                         Ke=CreateKMatrixBalancedthickness_CG();
    2460                         break;
    2461                 case P1DGEnum:
    2462                         Ke=CreateKMatrixBalancedthickness_DG();
    2463                         break;
    2464                 default:
    2465                         ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
    2466         }
    2467 
    2468         /*Transpose and return Ke*/
    2469         Ke->Transpose();
    2470         return Ke;
    2471 }
    2472 /*}}}*/
    2473 /*FUNCTION Tria::CreateKMatrixBalancedthickness {{{1*/
    2474 ElementMatrix* Tria::CreateKMatrixBalancedthickness(void){
    2475 
    2476         switch(GetElementType()){
    2477                 case P1Enum:
    2478                         return CreateKMatrixBalancedthickness_CG();
    2479                 case P1DGEnum:
    2480                         return CreateKMatrixBalancedthickness_DG();
    2481                 default:
    2482                         ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
    2483         }
    2484 
    2485 }
    2486 /*}}}*/
    2487 /*FUNCTION Tria::CreateKMatrixBalancedthickness_CG {{{1*/
    2488 ElementMatrix* Tria::CreateKMatrixBalancedthickness_CG(void){
    2489 
    2490         /*Constants*/
    2491         const int    numdof=NDOF1*NUMVERTICES;
    2492 
    2493         /*Intermediaries */
    2494         int        artdiff;
    2495         int        i,j,ig,dim;
    2496         double     Jdettria ,vx,vy,dvxdx,dvydy;
    2497         double     dvx[2],dvy[2];
    2498         double     xyz_list[NUMVERTICES][3];
    2499         double     L[NUMVERTICES];
    2500         double     B[2][NUMVERTICES];
    2501         double     Bprime[2][NUMVERTICES];
    2502         double     K[2][2]                          = {0.0};
    2503         double     KDL[2][2]                        = {0.0};
    2504         double     DL[2][2]                         = {0.0};
    2505         double     DLprime[2][2]                    = {0.0};
    2506         double     DL_scalar;
    2507         double     Ke_gg_gaussian[numdof][numdof]   = {0.0};
    2508         double     Ke_gg_thickness1[numdof][numdof] = {0.0};
    2509         double     Ke_gg_thickness2[numdof][numdof] = {0.0};
    2510         GaussTria *gauss                            = NULL;
    2511 
    2512         /*Initialize Element matrix and return if necessary*/
    2513         if(IsOnWater()) return NULL;
    2514         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2515 
    2516         /*Retrieve all Inputs and parameters: */
    2517         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2518         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    2519         this->parameters->FindParam(&dim,DimEnum);
    2520         Input* vxaverage_input=NULL;
    2521         Input* vyaverage_input=NULL;
    2522         if(dim==2){
    2523                 vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
    2524                 vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
    2525         }
    2526         else{
    2527                 vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
    2528                 vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
    2529         }
    2530 
    2531         /*Create Artificial diffusivity once for all if requested*/
    2532         if(artdiff){
    2533                 gauss=new GaussTria();
    2534                 gauss->GaussCenter();
    2535                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    2536                 delete gauss;
    2537 
    2538                 vxaverage_input->GetParameterAverage(&vx);
    2539                 vyaverage_input->GetParameterAverage(&vy);
    2540                 K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(vx);
    2541                 K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(vy);
    2542         }
    2543 
    2544         /*Start looping on the number of gaussian points:*/
    2545         gauss=new GaussTria(2);
    2546         for (ig=gauss->begin();ig<gauss->end();ig++){
    2547 
    2548                 gauss->GaussPoint(ig);
    2549 
    2550                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    2551                 GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
    2552                 GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
    2553 
    2554                 vxaverage_input->GetParameterValue(&vx,gauss);
    2555                 vyaverage_input->GetParameterValue(&vy,gauss);
    2556                 vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
    2557                 vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
    2558 
    2559                 dvxdx=dvx[0];
    2560                 dvydy=dvy[1];
    2561                 DL_scalar=gauss->weight*Jdettria;
    2562 
    2563                 DL[0][0]=DL_scalar*dvxdx;
    2564                 DL[1][1]=DL_scalar*dvydy;
    2565 
    2566                 DLprime[0][0]=DL_scalar*vx;
    2567                 DLprime[1][1]=DL_scalar*vy;
    2568 
    2569                 TripleMultiply( &B[0][0],2,numdof,1,
    2570                                         &DL[0][0],2,2,0,
    2571                                         &B[0][0],2,numdof,0,
    2572                                         &Ke_gg_thickness1[0][0],0);
    2573 
    2574                 TripleMultiply( &B[0][0],2,numdof,1,
    2575                                         &DLprime[0][0],2,2,0,
    2576                                         &Bprime[0][0],2,numdof,0,
    2577                                         &Ke_gg_thickness2[0][0],0);
    2578 
    2579                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
    2580                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
    2581 
    2582                 if(artdiff){
    2583                         KDL[0][0]=DL_scalar*K[0][0];
    2584                         KDL[1][1]=DL_scalar*K[1][1];
    2585 
    2586                         TripleMultiply( &Bprime[0][0],2,numdof,1,
    2587                                                 &KDL[0][0],2,2,0,
    2588                                                 &Bprime[0][0],2,numdof,0,
    2589                                                 &Ke_gg_gaussian[0][0],0);
    2590 
    2591                         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    2592                 }
    2593         }
    2594 
    2595         /*Clean up and return*/
    2596         delete gauss;
    2597         return Ke;
    2598 }
    2599 /*}}}*/
    2600 /*FUNCTION Tria::CreateKMatrixBalancedthickness_DG {{{1*/
    2601 ElementMatrix* Tria::CreateKMatrixBalancedthickness_DG(void){
    2602 
    2603         /*Constants*/
    2604         const int  numdof=NDOF1*NUMVERTICES;
    2605 
    2606         /*Intermediaries*/
    2607         int        i,j,ig,dim;
    2608         double     vx,vy,Jdettria;
    2609         double     xyz_list[NUMVERTICES][3];
    2610         double     B[2][NUMVERTICES];
    2611         double     Bprime[2][NUMVERTICES];
    2612         double     DL[2][2]={0.0};
    2613         double     DL_scalar;
    2614         double     Ke_gg[numdof][numdof]={0.0};
    2615         GaussTria  *gauss=NULL;
    2616 
    2617         /*Initialize Element matrix and return if necessary*/
    2618         if(IsOnWater()) return NULL;
    2619         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2620 
    2621         /*Retrieve all inputs and parameters*/
    2622         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2623         this->parameters->FindParam(&dim,DimEnum);
    2624         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    2625         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    2626 
    2627         /*Start looping on the number of gaussian points:*/
    2628         gauss=new GaussTria(2);
    2629         for (ig=gauss->begin();ig<gauss->end();ig++){
    2630 
    2631                 gauss->GaussPoint(ig);
    2632 
    2633                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    2634                 /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
    2635                 GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
    2636                 GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
    2637 
    2638                 vx_input->GetParameterValue(&vx,gauss);
    2639                 vy_input->GetParameterValue(&vy,gauss);
    2640 
    2641                 DL_scalar=-gauss->weight*Jdettria;
    2642                 DL[0][0]=DL_scalar*vx;
    2643                 DL[1][1]=DL_scalar*vy;
    2644 
    2645                 TripleMultiply( &B[0][0],2,numdof,1,
    2646                                         &DL[0][0],2,2,0,
    2647                                         &Bprime[0][0],2,numdof,0,
    2648                                         &Ke_gg[0][0],0);
    2649 
    2650                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
    2651         }
    2652 
    2653         /*Clean up and return*/
    2654         delete gauss;
    2655         return Ke;
    2656 }
    2657 /*}}}*/
    2658 /*FUNCTION Tria::CreateKMatrixBalancedvelocities {{{1*/
    2659 ElementMatrix* Tria::CreateKMatrixBalancedvelocities(void){
    2660 
    2661         /*Constants*/
    2662         const int    numdof=NDOF1*NUMVERTICES;
    2663 
    2664         /*Intermediaries */
    2665         int     artdiff;
    2666         int     i,j,ig,dim;
    2667         double  nx,ny,norm,Jdettria;
    2668         double  dvx[2],dvy[2];
    2669         double  vx,vy,dvxdx,dvydy;
    2670         double  v_gauss[2]={0.0};
    2671         double  surface_normal[3];
    2672         double  surface_list[3];
    2673         double  xyz_list[NUMVERTICES][3];
    2674         double  B[2][NUMVERTICES];
    2675         double  Bprime[2][NUMVERTICES];
    2676         double  K[2][2]={0.0};
    2677         double  KDL[2][2]={0.0};
    2678         double  DLprime[2][2]={0.0};
    2679         double  DL_scalar;
    2680         double  Ke_gg_gaussian[numdof][numdof]   = {0.0};
    2681         double  Ke_gg_velocities[numdof][numdof] = {0.0};
    2682         GaussTria *gauss=NULL;
    2683 
    2684         /*Initialize Element matrix and return if necessary*/
    2685         if(IsOnWater()) return NULL;
    2686         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    2687 
    2688         /*Retrieve all inputs and parameters*/
    2689         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2690         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    2691         this->parameters->FindParam(&dim,DimEnum);
    2692         Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
    2693         Input* vxaverage_input=NULL;
    2694         Input* vyaverage_input=NULL;
    2695         if(dim==2){
    2696                 vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
    2697                 vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
    2698         }
    2699         else{
    2700                 vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
    2701                 vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
    2702         }
    2703 
    2704         /*Modify z so that it reflects the surface*/
    2705         GetParameterListOnVertices(&surface_list[0],SurfaceEnum);
    2706         for(i=0;i<NUMVERTICES;i++) xyz_list[i][2]=surface_list[i];
    2707 
    2708         /*Get normal vector to the surface*/
    2709         vxaverage_input->GetParameterAverage(&nx);
    2710         vyaverage_input->GetParameterAverage(&ny);
    2711         if(nx==0 && ny==0){
    2712                 SurfaceNormal(&surface_normal[0],xyz_list);
    2713                 nx=surface_normal[0];
    2714                 ny=surface_normal[1];
    2715         }
    2716         if(nx==0 && ny==0){
    2717                 nx=0; ny=1;
    2718         }
    2719         norm=pow( pow(nx,2)+pow(ny,2) , (double).5);
    2720         nx=nx/norm; ny=ny/norm;
    2721 
    2722         //Create Artificial diffusivity once for all if requested
    2723         if(artdiff){
    2724                 gauss=new GaussTria();
    2725                 gauss->GaussCenter();
    2726                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    2727                 delete gauss;
    2728 
    2729                 vxaverage_input->GetParameterAverage(&v_gauss[0]);
    2730                 vyaverage_input->GetParameterAverage(&v_gauss[1]);
    2731                 K[0][0]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]); //pow should be zero!!
    2732                 K[1][1]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
    2733         }
    2734 
    2735         /* Start  looping on the number of gaussian points: */
    2736         gauss=new GaussTria(2);
    2737         for (ig=gauss->begin();ig<gauss->end();ig++){
    2738 
    2739                 gauss->GaussPoint(ig);
    2740 
    2741                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    2742                 GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
    2743                 GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
    2744 
    2745                 vxaverage_input->GetParameterValue(&vx,gauss);
    2746                 vyaverage_input->GetParameterValue(&vy,gauss);
    2747                 vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
    2748                 vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
    2749 
    2750                 dvxdx=dvx[0];
    2751                 dvydy=dvy[1];
    2752                 DL_scalar=gauss->weight*Jdettria;
    2753 
    2754                 DLprime[0][0]=DL_scalar*nx;
    2755                 DLprime[1][1]=DL_scalar*ny;
    2756 
    2757                 TripleMultiply( &B[0][0],2,numdof,1,
    2758                                         &DLprime[0][0],2,2,0,
    2759                                         &Bprime[0][0],2,numdof,0,
    2760                                         &Ke_gg_velocities[0][0],0);
    2761 
    2762                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_velocities[i][j];
    2763 
    2764                 if(artdiff){
    2765                         KDL[0][0]=DL_scalar*K[0][0];
    2766                         KDL[1][1]=DL_scalar*K[1][1];
    2767 
    2768                         TripleMultiply( &Bprime[0][0],2,numdof,1,
    2769                                                 &KDL[0][0],2,2,0,
    2770                                                 &Bprime[0][0],2,numdof,0,
    2771                                                 &Ke_gg_gaussian[0][0],0);
    2772 
    2773                         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    2774                 }
    2775         }
    2776 
    2777         /*Clean up and return*/
    2778         delete gauss;
    2779         return Ke;
    2780 }
    2781 /*}}}*/
    2782 /*FUNCTION Tria::CreateKMatrixDiagnosticMacAyeal {{{1*/
    2783 ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyeal(void){
    2784        
    2785         /*compute all stiffness matrices for this element*/
    2786         ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyealViscous();
    2787         ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyealFriction();
    2788         ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
    2789 
    2790         /*clean-up and return*/
    2791         delete Ke1;
    2792         delete Ke2;
    2793         return Ke;
    2794 
    2795 }
    2796 /*}}}*/
    2797 /*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealViscous{{{1*/
    2798 ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealViscous(void){
    2799 
    2800         /*Constants*/
    2801         const int  numdof=NDOF2*NUMVERTICES;
    2802 
    2803         /*Intermediaries*/
    2804         int        i,j,ig;
    2805         double     xyz_list[NUMVERTICES][3];
    2806         double     viscosity,newviscosity,oldviscosity;
    2807         double     viscosity_overshoot,thickness,Jdet;
    2808         double     epsilon[3],oldepsilon[3];    /* epsilon=[exx,eyy,exy];    */
    2809         double     B[3][numdof];
    2810         double     Bprime[3][numdof];
    2811         double     D[3][3]   = {0.0};
    2812         double     D_scalar;
    2813         double     Ke_g[numdof][numdof];
    2814         GaussTria *gauss = NULL;
    2815 
    2816         /*Initialize Element matrix and return if necessary*/
    2817         if(IsOnWater()) return NULL;
    2818         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
    2819 
    2820         /*Retrieve all inputs and parameters*/
    2821         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2822         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    2823         Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
    2824         Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
    2825         Input* vxold_input=inputs->GetInput(VxOldEnum);         ISSMASSERT(vxold_input);
    2826         Input* vyold_input=inputs->GetInput(VyOldEnum);         ISSMASSERT(vyold_input);
    2827         this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
    2828 
    2829         /* Start  looping on the number of gaussian points: */
    2830         gauss=new GaussTria(2);
    2831         for (ig=gauss->begin();ig<gauss->end();ig++){
    2832 
    2833                 gauss->GaussPoint(ig);
    2834 
    2835                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    2836                 GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss);
    2837                 GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss);
    2838 
    2839                 this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
    2840                 this->GetStrainRate2d(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
    2841                 matice->GetViscosity2d(&viscosity, &epsilon[0]);
    2842                 matice->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
    2843                 thickness_input->GetParameterValue(&thickness, gauss);
    2844 
    2845                 newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
    2846                 D_scalar=2*newviscosity*thickness*gauss->weight*Jdet;
    2847                 for (i=0;i<3;i++) D[i][i]=D_scalar;
    2848 
    2849                 TripleMultiply(&B[0][0],3,numdof,1,
    2850                                         &D[0][0],3,3,0,
    2851                                         &Bprime[0][0],3,numdof,0,
    2852                                         &Ke_g[0][0],0);
    2853 
    2854                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
    2855         }
    2856 
    2857         /*Clean up and return*/
    2858         delete gauss;
    2859         return Ke;
    2860 }
    2861 /*}}}*/
    2862 /*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealFriction {{{1*/
    2863 ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealFriction(void){
    2864 
    2865         /*Constants*/
    2866         const int  numdof=NDOF2*NUMVERTICES;
    2867 
    2868         /*Intermediaries*/
    2869         int        i,j,ig;
    2870         int        analysis_type,drag_type;
    2871         double     MAXSLOPE  = .06; // 6 %
    2872         double     MOUNTAINKEXPONENT = 10;
    2873         double     slope_magnitude,alpha2;
    2874         double     Jdet;
    2875         double     L[2][numdof];
    2876         double     DL[2][2]  = {{ 0,0 },{0,0}};
    2877         double     Ke_g[numdof][numdof];
    2878         double     DL_scalar;
    2879         double     slope[2]  = {0.0,0.0};
    2880         double     xyz_list[NUMVERTICES][3];
    2881         Friction  *friction = NULL;
    2882         GaussTria *gauss    = NULL;
    2883 
    2884         /*Initialize Element matrix and return if necessary*/
    2885         if(IsOnWater() || IsOnShelf()) return NULL;
    2886         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
    2887 
    2888         /*Retrieve all inputs and parameters*/
    2889         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2890         Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
    2891         Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
    2892         Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
    2893         Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
    2894         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    2895         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    2896 
    2897         /*build friction object, used later on: */
    2898         if (drag_type!=2) ISSMERROR(" non-viscous friction not supported yet!");
    2899         friction=new Friction("2d",inputs,matpar,analysis_type);
    2900 
    2901         /* Start  looping on the number of gaussian points: */
    2902         gauss=new GaussTria(2);
    2903         for (ig=gauss->begin();ig<gauss->end();ig++){
    2904 
    2905                 gauss->GaussPoint(ig);
    2906 
    2907                 // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
    2908                 //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
    2909                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    2910                 slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
    2911                 if(slope_magnitude>MAXSLOPE) alpha2=pow((double)10,MOUNTAINKEXPONENT);
    2912                 else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
    2913 
    2914                 GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
    2915                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    2916                 DL_scalar=alpha2*gauss->weight*Jdet;
    2917                 for (i=0;i<2;i++) DL[i][i]=DL_scalar;
    2918                
    2919                 TripleMultiply( &L[0][0],2,numdof,1,
    2920                                         &DL[0][0],2,2,0,
    2921                                         &L[0][0],2,numdof,0,
    2922                                         &Ke_g[0][0],0);
    2923 
    2924                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
    2925         }
    2926 
    2927         /*Clean up and return*/
    2928         delete gauss;
    2929         delete friction;
    2930         return Ke;
    2931 }
    2932 /*}}}*/
    2933 /*FUNCTION Tria::CreateKMatrixCouplingMacAyealPattynFriction {{{1*/
    2934 ElementMatrix* Tria::CreateKMatrixCouplingMacAyealPattynFriction(void){
    2935 
    2936         /*Constants*/
    2937         const int numdof        = NDOF2 *NUMVERTICES;
    2938         const int numdoftotal   = NDOF4 *NUMVERTICES;
    2939        
    2940         /*Intermediaries */
    2941         int       i,j,ig,analysis_type,drag_type;
    2942         double    Jdet,slope_magnitude,alpha2;
    2943         double    xyz_list[NUMVERTICES][3];
    2944         double    slope[2]={0.0,0.0};
    2945         double    MAXSLOPE=.06; // 6 %
    2946         double    MOUNTAINKEXPONENT=10;
    2947         double    L[2][numdof];
    2948         double    DL[2][2]                  ={{ 0,0 },{0,0}}; //for basal drag
    2949         double    DL_scalar;
    2950         double    Ke_gg[numdof][numdof]     ={0.0};
    2951         double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
    2952         Friction  *friction = NULL;
    2953         GaussTria *gauss=NULL;
    2954 
    2955         /*Initialize Element matrix and return if necessary*/
    2956         if(IsOnWater() || IsOnShelf()) return NULL;
    2957         ElementMatrix* Ke1=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
    2958         ElementMatrix* Ke2=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
    2959         ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
    2960         delete Ke1; delete Ke2;
    2961 
    2962         /*retrieve inputs :*/
    2963         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    2964         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    2965         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    2966         Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
    2967         Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
    2968         Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
    2969         Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
    2970 
    2971         /*build friction object, used later on: */
    2972         if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
    2973         friction=new Friction("2d",inputs,matpar,analysis_type);
    2974 
    2975         /* Start  looping on the number of gaussian points: */
    2976         gauss=new GaussTria(2);
    2977         for (ig=gauss->begin();ig<gauss->end();ig++){
    2978 
    2979                 gauss->GaussPoint(ig);
    2980 
    2981                 /*Friction: */
    2982                 friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
    2983 
    2984                 // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
    2985                 //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
    2986                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    2987                 slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
    2988 
    2989                 if (slope_magnitude>MAXSLOPE){
    2990                         alpha2=pow((double)10,MOUNTAINKEXPONENT);
    2991                 }
    2992 
    2993                 /* Get Jacobian determinant: */
    2994                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    2995 
    2996                 /*Get L matrix: */
    2997                 GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
    2998 
    2999                
    3000                 DL_scalar=alpha2*gauss->weight*Jdet;
    3001                 for (i=0;i<2;i++){
    3002                         DL[i][i]=DL_scalar;
    3003                 }
    3004                
    3005                 /*  Do the triple producte tL*D*L: */
    3006                 TripleMultiply( &L[0][0],2,numdof,1,
    3007                                         &DL[0][0],2,2,0,
    3008                                         &L[0][0],2,numdof,0,
    3009                                         &Ke_gg_gaussian[0][0],0);
    3010 
    3011                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
    3012         }
    3013 
    3014         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdoftotal+(numdof+j)]+=Ke_gg[i][j];
    3015         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[(i+numdof)*numdoftotal+j]+=Ke_gg[i][j];
    3016 
    3017         /*Clean up and return*/
    3018         delete gauss;
    3019         delete friction;
    3020         return Ke;
    3021 }       
    3022 /*}}}*/
    3023 /*FUNCTION Tria::CreateKMatrixDiagnosticPattynFriction {{{1*/
    3024 ElementMatrix* Tria::CreateKMatrixDiagnosticPattynFriction(void){
    3025 
    3026         /*Constants*/
    3027         const int numdof   = NDOF2*NUMVERTICES;
    3028        
    3029         /*Intermediaries */
    3030         int       i,j,ig;
    3031         int       analysis_type,drag_type;
    3032         double    xyz_list[NUMVERTICES][3];
    3033         double    slope_magnitude,alpha2,Jdet;
    3034         double    slope[2]={0.0,0.0};
    3035         double    MAXSLOPE=.06; // 6 %
    3036         double    MOUNTAINKEXPONENT=10;
    3037         double    L[2][numdof];
    3038         double    DL[2][2]={{ 0,0 },{0,0}}; //for basal drag
    3039         double    DL_scalar;
    3040         double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
    3041         Friction  *friction = NULL;
    3042         GaussTria *gauss=NULL;
    3043 
    3044         /*Initialize Element matrix and return if necessary*/
    3045         if(IsOnWater() || IsOnShelf()) return NULL;
    3046         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
    3047 
    3048         /*Retrieve all inputs and parameters*/
    3049         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3050         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    3051         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    3052         Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
    3053         Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
    3054         Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
    3055         Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
    3056 
    3057         /*build friction object, used later on: */
    3058         if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
    3059         friction=new Friction("2d",inputs,matpar,analysis_type);
    3060 
    3061         /* Start  looping on the number of gaussian points: */
    3062         gauss=new GaussTria(2);
    3063         for (ig=gauss->begin();ig<gauss->end();ig++){
    3064 
    3065                 gauss->GaussPoint(ig);
    3066 
    3067                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    3068                 GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
    3069 
    3070                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    3071                 friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum); // TO UNCOMMENT
    3072                 slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
    3073 
    3074                 // If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case,
    3075                 //velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
    3076                 if (slope_magnitude>MAXSLOPE){
    3077                         alpha2=pow((double)10,MOUNTAINKEXPONENT);
    3078                 }
    3079                
    3080                 DL_scalar=alpha2*gauss->weight*Jdet;
    3081                 for (i=0;i<2;i++) DL[i][i]=DL_scalar;
    3082                
    3083                 TripleMultiply( &L[0][0],2,numdof,1,
    3084                                         &DL[0][0],2,2,0,
    3085                                         &L[0][0],2,numdof,0,
    3086                                         &Ke_gg_gaussian[0][0],0);
    3087 
    3088                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    3089         }
    3090 
    3091         /*Clean up and return*/
    3092         delete gauss;
    3093         delete friction;
    3094         return Ke;
    3095 }       
    3096 /*}}}*/
    3097 /*FUNCTION Tria::CreateKMatrixDiagnosticHutter{{{1*/
    3098 ElementMatrix* Tria::CreateKMatrixDiagnosticHutter(void){
    3099 
    3100         /*Intermediaries*/
    3101         const int numdof=NUMVERTICES*NDOF2;
    3102         int    i,connectivity;
    3103 
    3104         /*Initialize Element matrix and return if necessary*/
    3105         if(IsOnWater()) return NULL;
    3106         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3107 
    3108         /*Create Element matrix*/
    3109         for(i=0;i<NUMVERTICES;i++){
    3110                 connectivity=nodes[i]->GetConnectivity();
    3111                 Ke->values[(2*i)*numdof  +(2*i)  ]=1/(double)connectivity;
    3112                 Ke->values[(2*i+1)*numdof+(2*i+1)]=1/(double)connectivity;
    3113         }
    3114 
    3115         /*Clean up and return*/
    3116         return Ke;
    3117 }
    3118 /*}}}*/
    3119 /*FUNCTION Tria::CreateKMatrixDiagnosticVertSurface {{{1*/
    3120 ElementMatrix* Tria::CreateKMatrixDiagnosticVertSurface(void){
    3121 
    3122         /*Constants*/
    3123         const int numdof=NDOF1*NUMVERTICES;
    3124 
    3125         /*Intermediaries */
    3126         int       i,j,ig;
    3127         double    xyz_list[NUMVERTICES][3];
    3128         double    surface_normal[3];
    3129         double    Jdet,DL_scalar;
    3130         double    L[3];
    3131         GaussTria *gauss=NULL;
    3132         double Ke_g[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
    3133 
    3134         /*Initialize Element matrix and return if necessary*/
    3135         if(IsOnWater()) return NULL;
    3136         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3137 
    3138         /*Retrieve all inputs and parameters*/
    3139         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3140         SurfaceNormal(&surface_normal[0],xyz_list);
    3141 
    3142         /* Start  looping on the number of gaussian points: */
    3143         gauss=new GaussTria(2);
    3144         for (ig=gauss->begin();ig<gauss->end();ig++){
    3145 
    3146                 gauss->GaussPoint(ig);
    3147 
    3148                 GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
    3149                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3150 
    3151                 /**********************Do not forget the sign**********************************/
    3152                 DL_scalar=- gauss->weight*Jdet*surface_normal[2];
    3153                 /******************************************************************************/
    3154 
    3155                 TripleMultiply( L,1,3,1,
    3156                                         &DL_scalar,1,1,0,
    3157                                         L,1,3,0,
    3158                                         &Ke_g[0][0],0);
    3159 
    3160                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
    3161         }
    3162 
    3163         /*Clean up and return*/
    3164         delete gauss;
    3165         return Ke;
    3166 }
    3167 /*}}}*/
    3168 /*FUNCTION Tria::CreateKMatrixMelting {{{1*/
    3169 ElementMatrix* Tria::CreateKMatrixMelting(void){
    3170 
    3171         /*Constants*/
    3172         const int  numdof=NUMVERTICES*NDOF1;
    3173 
    3174         /*Intermediaries */
    3175         int        i,j,ig;
    3176         double     heatcapacity,latentheat;
    3177         double     Jdet,D_scalar;
    3178         double     xyz_list[NUMVERTICES][3];
    3179         double     L[3];
    3180         double     Ke_gaussian[numdof][numdof]={0.0};
    3181         GaussTria *gauss=NULL;
    3182 
    3183         /*Initialize Element matrix and return if necessary*/
    3184         if(IsOnWater()) return NULL;
    3185         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3186 
    3187         /*Retrieve all inputs and parameters*/
    3188         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3189         latentheat=matpar->GetLatentHeat();
    3190         heatcapacity=matpar->GetHeatCapacity();
    3191 
    3192         /* Start looping on the number of gauss  (nodes on the bedrock) */
    3193         gauss=new GaussTria(2);
    3194         for (ig=gauss->begin();ig<gauss->end();ig++){
    3195 
    3196                 gauss->GaussPoint(ig);
    3197 
    3198                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3199                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
    3200 
    3201                 D_scalar=latentheat/heatcapacity*gauss->weight*Jdet;
    3202 
    3203                 TripleMultiply(&L[0],numdof,1,0,
    3204                                         &D_scalar,1,1,0,
    3205                                         &L[0],1,numdof,0,
    3206                                         &Ke_gaussian[0][0],0);
    3207 
    3208                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
    3209         }
    3210 
    3211         /*Clean up and return*/
    3212         delete gauss;
    3213         return Ke;
    3214 }
    3215 /*}}}*/
    3216 /*FUNCTION Tria::CreateKMatrixPrognostic {{{1*/
    3217 ElementMatrix* Tria::CreateKMatrixPrognostic(void){
    3218 
    3219         switch(GetElementType()){
    3220                 case P1Enum:
    3221                         return CreateKMatrixPrognostic_CG();
    3222                 case P1DGEnum:
    3223                         return CreateKMatrixPrognostic_DG();
    3224                 default:
    3225                         ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
    3226         }
    3227 
    3228 }
    3229 /*}}}*/
    3230 /*FUNCTION Tria::CreateKMatrixPrognostic_CG {{{1*/
    3231 ElementMatrix* Tria::CreateKMatrixPrognostic_CG(void){
    3232 
    3233         /*Constants*/
    3234         const int    numdof=NDOF1*NUMVERTICES;
    3235 
    3236         /*Intermediaries */
    3237         int        artdiff;
    3238         int        i,j,ig,dim;
    3239         double     Jdettria,DL_scalar,dt;
    3240         double     vx,vy,dvxdx,dvydy;
    3241         double     dvx[2],dvy[2];
    3242         double     v_gauss[2]={0.0};
    3243         double     xyz_list[NUMVERTICES][3];
    3244         double     L[NUMVERTICES];
    3245         double     B[2][NUMVERTICES];
    3246         double     Bprime[2][NUMVERTICES];
    3247         double     K[2][2]                        ={0.0};
    3248         double     KDL[2][2]                      ={0.0};
    3249         double     DL[2][2]                        ={0.0};
    3250         double     DLprime[2][2]                   ={0.0};
    3251         double     Ke_gg_gaussian[numdof][numdof]  ={0.0};
    3252         double     Ke_gg_thickness1[numdof][numdof]={0.0};
    3253         double     Ke_gg_thickness2[numdof][numdof]={0.0};
    3254         GaussTria *gauss=NULL;
    3255 
    3256         /*Initialize Element matrix and return if necessary*/
    3257         if(IsOnWater()) return NULL;
    3258         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3259 
    3260         /*Retrieve all inputs and parameters*/
    3261         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3262         this->inputs->GetParameterValue(&dt,DtEnum);
    3263         this->parameters->FindParam(&dim,DimEnum);
    3264         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    3265         Input* vxaverage_input=NULL;
    3266         Input* vyaverage_input=NULL;
    3267         if(dim==2){
    3268                 vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
    3269                 vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
    3270         }
    3271         else{
    3272                 vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
    3273                 vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
    3274         }
    3275 
    3276         //Create Artificial diffusivity once for all if requested
    3277         if(artdiff){
    3278                 gauss=new GaussTria();
    3279                 gauss->GaussCenter();
    3280                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3281                 delete gauss;
    3282 
    3283                 vxaverage_input->GetParameterAverage(&v_gauss[0]);
    3284                 vyaverage_input->GetParameterAverage(&v_gauss[1]);
    3285 
    3286                 K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]);
    3287                 K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
    3288         }
    3289 
    3290         /* Start  looping on the number of gaussian points: */
    3291         gauss=new GaussTria(2);
    3292         for (ig=gauss->begin();ig<gauss->end();ig++){
    3293 
    3294                 gauss->GaussPoint(ig);
    3295 
    3296                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3297                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3298 
    3299                 vxaverage_input->GetParameterValue(&vx,gauss);
    3300                 vyaverage_input->GetParameterValue(&vy,gauss);
    3301                 vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
    3302                 vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
    3303 
    3304                 DL_scalar=gauss->weight*Jdettria;
    3305 
    3306                 TripleMultiply( &L[0],1,numdof,1,
    3307                                         &DL_scalar,1,1,0,
    3308                                         &L[0],1,numdof,0,
    3309                                         &Ke_gg_gaussian[0][0],0);
    3310 
    3311                 GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
    3312                 GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
    3313 
    3314                 dvxdx=dvx[0];
    3315                 dvydy=dvy[1];
    3316                 DL_scalar=dt*gauss->weight*Jdettria;
    3317 
    3318                 DL[0][0]=DL_scalar*dvxdx;
    3319                 DL[1][1]=DL_scalar*dvydy;
    3320                 DLprime[0][0]=DL_scalar*vx;
    3321                 DLprime[1][1]=DL_scalar*vy;
    3322 
    3323                 TripleMultiply( &B[0][0],2,numdof,1,
    3324                                         &DL[0][0],2,2,0,
    3325                                         &B[0][0],2,numdof,0,
    3326                                         &Ke_gg_thickness1[0][0],0);
    3327 
    3328                 TripleMultiply( &B[0][0],2,numdof,1,
    3329                                         &DLprime[0][0],2,2,0,
    3330                                         &Bprime[0][0],2,numdof,0,
    3331                                         &Ke_gg_thickness2[0][0],0);
    3332 
    3333                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    3334                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
    3335                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
    3336 
    3337                 if(artdiff){
    3338                         KDL[0][0]=DL_scalar*K[0][0];
    3339                         KDL[1][1]=DL_scalar*K[1][1];
    3340 
    3341                         TripleMultiply( &Bprime[0][0],2,numdof,1,
    3342                                                 &KDL[0][0],2,2,0,
    3343                                                 &Bprime[0][0],2,numdof,0,
    3344                                                 &Ke_gg_gaussian[0][0],0);
    3345 
    3346                         for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
    3347                 }
    3348         }
    3349 
    3350         /*Clean up and return*/
    3351         delete gauss;
    3352         return Ke;
    3353 }
    3354 /*}}}*/
    3355 /*FUNCTION Tria::CreateKMatrixPrognostic_DG {{{1*/
    3356 ElementMatrix* Tria::CreateKMatrixPrognostic_DG(void){
    3357 
    3358         /*Constants*/
    3359         const int    numdof=NDOF1*NUMVERTICES;
    3360 
    3361         /*Intermediaries */
    3362         int        i,j,ig,dim;
    3363         double     xyz_list[NUMVERTICES][3];
    3364         double     Jdettria,dt,vx,vy;
    3365         double     L[NUMVERTICES];
    3366         double     B[2][NUMVERTICES];
    3367         double     Bprime[2][NUMVERTICES];
    3368         double     DL[2][2]={0.0};
    3369         double     DLprime[2][2]={0.0};
    3370         double     DL_scalar;
    3371         double     Ke_gg1[numdof][numdof]={0.0};
    3372         double     Ke_gg2[numdof][numdof]={0.0};
    3373         GaussTria  *gauss=NULL;
    3374 
    3375         /*Initialize Element matrix and return if necessary*/
    3376         if(IsOnWater()) return NULL;
    3377         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3378 
    3379         /*Retrieve all inputs and parameters*/
    3380         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3381         this->inputs->GetParameterValue(&dt,DtEnum);
    3382         this->parameters->FindParam(&dim,DimEnum);
    3383         Input* vxaverage_input=NULL;
    3384         Input* vyaverage_input=NULL;
    3385         if(dim==2){
    3386                 vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
    3387                 vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
    3388         }
    3389         else{
    3390                 vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
    3391                 vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
    3392         }
    3393 
    3394         /* Start  looping on the number of gaussian points: */
    3395         gauss=new GaussTria(2);
    3396         for (ig=gauss->begin();ig<gauss->end();ig++){
    3397 
    3398                 gauss->GaussPoint(ig);
    3399 
    3400                 vxaverage_input->GetParameterValue(&vx,gauss);
    3401                 vyaverage_input->GetParameterValue(&vy,gauss);
    3402 
    3403                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3404                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3405 
    3406                 DL_scalar=gauss->weight*Jdettria;
    3407 
    3408                 TripleMultiply( &L[0],1,numdof,1,
    3409                                         &DL_scalar,1,1,0,
    3410                                         &L[0],1,numdof,0,
    3411                                         &Ke_gg1[0][0],0);
    3412 
    3413                 /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
    3414                 GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
    3415                 GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
    3416 
    3417                 DL_scalar=-dt*gauss->weight*Jdettria;
    3418 
    3419                 DLprime[0][0]=DL_scalar*vx;
    3420                 DLprime[1][1]=DL_scalar*vy;
    3421 
    3422                 TripleMultiply( &B[0][0],2,numdof,1,
    3423                                         &DLprime[0][0],2,2,0,
    3424                                         &Bprime[0][0],2,numdof,0,
    3425                                         &Ke_gg2[0][0],0);
    3426 
    3427                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg1[i][j];
    3428                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg2[i][j];
    3429         }
    3430 
    3431         /*Clean up and return*/
    3432         delete gauss;
    3433         return Ke;
    3434 }
    3435 /*}}}*/
    3436 /*FUNCTION Tria::CreateKMatrixSlope {{{1*/
    3437 ElementMatrix* Tria::CreateKMatrixSlope(void){
    3438 
    3439         /*constants: */
    3440         const int    numdof=NDOF1*NUMVERTICES;
    3441 
    3442         /* Intermediaries */
    3443         int        i,j,ig;
    3444         double     DL_scalar,Jdet;
    3445         double     xyz_list[NUMVERTICES][3];
    3446         double     L[1][3];
    3447         double     Ke_g[numdof][numdof];
    3448         GaussTria *gauss = NULL;
    3449 
    3450         /*Initialize Element matrix and return if necessary*/
    3451         if(IsOnWater()) return NULL;
    3452         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3453 
    3454         GetVerticesCoordinates(&xyz_list[0][0],nodes,NUMVERTICES);
    3455 
    3456         /* Start looping on the number of gaussian points: */
    3457         gauss=new GaussTria(2);
    3458         for (ig=gauss->begin();ig<gauss->end();ig++){
    3459 
    3460                 gauss->GaussPoint(ig);
    3461                
    3462                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    3463                 DL_scalar=gauss->weight*Jdet;
    3464 
    3465                 GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
    3466 
    3467                 TripleMultiply(&L[0][0],1,3,1,
    3468                                         &DL_scalar,1,1,0,
    3469                                         &L[0][0],1,3,0,
    3470                                         &Ke_g[0][0],0);
    3471 
    3472                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
    3473         }
    3474 
    3475         /*Clean up and return*/
    3476         delete gauss;
    3477         return Ke;
    3478 }
    3479 /*}}}*/
    3480 /*FUNCTION Tria::CreateKMatrixThermal {{{1*/
    3481 ElementMatrix* Tria::CreateKMatrixThermal(void){
    3482 
    3483         /*Constants*/
    3484         const int    numdof=NDOF1*NUMVERTICES;
    3485 
    3486         /*Intermediaries */
    3487         int       i,j,ig;
    3488         double    mixed_layer_capacity,thermal_exchange_velocity;
    3489         double    rho_ice,rho_water,heatcapacity;
    3490         double    Jdet,dt;
    3491         double    xyz_list[NUMVERTICES][3];
    3492         double    l1l2l3[NUMVERTICES];
    3493         double    D_scalar;
    3494         double    Ke_gaussian[numdof][numdof]={0.0};
    3495         GaussTria *gauss=NULL;
    3496 
    3497         /*Initialize Element matrix and return if necessary*/
    3498         if(IsOnWater() || !IsOnShelf()) return NULL;
    3499         ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
    3500 
    3501         /*Retrieve all inputs and parameters*/
    3502         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3503         this->inputs->GetParameterValue(&dt,DtEnum);
    3504         mixed_layer_capacity=matpar->GetMixedLayerCapacity();
    3505         thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
    3506         rho_water=matpar->GetRhoWater();
    3507         rho_ice=matpar->GetRhoIce();
    3508         heatcapacity=matpar->GetHeatCapacity();
    3509 
    3510         /* Start looping on the number of gauss (nodes on the bedrock) */
    3511         gauss=new GaussTria(2);
    3512         for (ig=gauss->begin();ig<gauss->end();ig++){
    3513 
    3514                 gauss->GaussPoint(ig);
    3515                
    3516                 GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
    3517                 GetNodalFunctions(&l1l2l3[0], gauss);
    3518                                
    3519                 D_scalar=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(heatcapacity*rho_ice);
    3520                 if(dt) D_scalar=dt*D_scalar;
    3521 
    3522                 TripleMultiply(&l1l2l3[0],numdof,1,0,
    3523                                         &D_scalar,1,1,0,
    3524                                         &l1l2l3[0],1,numdof,0,
    3525                                         &Ke_gaussian[0][0],0);
    3526 
    3527                 for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
    3528         }
    3529        
    3530         /*Clean up and return*/
    3531         delete gauss;
    3532         return Ke;
    3533 }
    3534 /*}}}*/
    3535 /*FUNCTION Tria::CreatePVectorBalancedthickness{{{1*/
    3536 ElementVector* Tria::CreatePVectorBalancedthickness(void){
    3537 
    3538         switch(GetElementType()){
    3539                 case P1Enum:
    3540                         return CreatePVectorBalancedthickness_CG();
    3541                         break;
    3542                 case P1DGEnum:
    3543                         return CreatePVectorBalancedthickness_DG();
    3544                 default:
    3545                         ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
    3546         }
    3547 }
    3548 /*}}}*/
    3549 /*FUNCTION Tria::CreatePVectorBalancedthickness_CG{{{1*/
    3550 ElementVector* Tria::CreatePVectorBalancedthickness_CG(void){
    3551 
    3552         /*Constants*/
    3553         const int    numdof=NDOF1*NUMVERTICES;
    3554        
    3555         /*Intermediaries */
    3556         int        i,j,ig;
    3557         double     xyz_list[NUMVERTICES][3];
    3558         double     dhdt_g,melting_g,accumulation_g,Jdettria;
    3559         double     L[NUMVERTICES];
    3560         GaussTria* gauss=NULL;
    3561 
    3562         /*Initialize Element vector and return if necessary*/
    3563         if(IsOnWater()) return NULL;
    3564         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3565 
    3566         /*Retrieve all inputs and parameters*/
    3567         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3568         Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
    3569         Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
    3570         Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
    3571        
    3572         /* Start  looping on the number of gaussian points: */
    3573         gauss=new GaussTria(2);
    3574         for(ig=gauss->begin();ig<gauss->end();ig++){
    3575 
    3576                 gauss->GaussPoint(ig);
    3577 
    3578                 accumulation_input->GetParameterValue(&accumulation_g,gauss);
    3579                 melting_input->GetParameterValue(&melting_g,gauss);
    3580                 dhdt_input->GetParameterValue(&dhdt_g,gauss);
    3581 
    3582                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3583                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3584 
    3585                 for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
    3586         }
    3587 
    3588         /*Clean up and return*/
    3589         delete gauss;
    3590         return pe;
    3591 }
    3592 /*}}}*/
    3593 /*FUNCTION Tria::CreatePVectorBalancedthickness_DG {{{1*/
    3594 ElementVector* Tria::CreatePVectorBalancedthickness_DG(void){
    3595 
    3596         /*Constants*/
    3597         const int    numdof=NDOF1*NUMVERTICES;
    3598 
    3599         /*Intermediaries */
    3600         int        i,j,ig;
    3601         double     xyz_list[NUMVERTICES][3];
    3602         double     melting_g,accumulation_g,dhdt_g,Jdettria;
    3603         double     L[NUMVERTICES];
    3604         GaussTria* gauss=NULL;
    3605 
    3606         /*Initialize Element vector and return if necessary*/
    3607         if(IsOnWater()) return NULL;
    3608         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3609 
    3610         /*Retrieve all inputs and parameters*/
    3611         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3612         Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
    3613         Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
    3614         Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
    3615 
    3616         /* Start  looping on the number of gaussian points: */
    3617         gauss=new GaussTria(2);
    3618         for(ig=gauss->begin();ig<gauss->end();ig++){
    3619 
    3620                 gauss->GaussPoint(ig);
    3621 
    3622                 accumulation_input->GetParameterValue(&accumulation_g,gauss);
    3623                 melting_input->GetParameterValue(&melting_g,gauss);
    3624                 dhdt_input->GetParameterValue(&dhdt_g,gauss);
    3625 
    3626                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3627                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3628 
    3629                 for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
    3630         }
    3631 
    3632         /*Clean up and return*/
    3633         delete gauss;
    3634         return pe;
    3635 }
    3636 /*}}}*/
    3637 /*FUNCTION Tria::CreatePVectorBalancedvelocities {{{1*/
    3638 ElementVector* Tria::CreatePVectorBalancedvelocities(void){
    3639 
    3640         /*Constants*/
    3641         const int    numdof=NDOF1*NUMVERTICES;
    3642 
    3643         /*Intermediaries */
    3644         int        i,j,ig;
    3645         double     xyz_list[NUMVERTICES][3];
    3646         double     Jdettria,accumulation_g,melting_g;
    3647         double     L[NUMVERTICES];
    3648         GaussTria* gauss=NULL;
    3649 
    3650         /*Initialize Element vector and return if necessary*/
    3651         if(IsOnWater()) return NULL;
    3652         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3653 
    3654         /*Retrieve all inputs and parameters*/
    3655         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3656         Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
    3657         Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
    3658 
    3659         /* Start  looping on the number of gaussian points: */
    3660         gauss=new GaussTria(2);
    3661         for(ig=gauss->begin();ig<gauss->end();ig++){
    3662 
    3663                 gauss->GaussPoint(ig);
    3664 
    3665                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    3666                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3667 
    3668                 accumulation_input->GetParameterValue(&accumulation_g,gauss);
    3669                 melting_input->GetParameterValue(&melting_g,gauss);
    3670 
    3671                 for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g)*L[i];
    3672         }
    3673 
    3674         /*Clean up and return*/
    3675         delete gauss;
    3676         return pe;
    3677 }
    3678 /*}}}*/
    3679 /*FUNCTION Tria::CreatePVectorDiagnosticBaseVert {{{1*/
    3680 ElementVector* Tria::CreatePVectorDiagnosticBaseVert(void){
    3681 
    3682         /*Constants*/
    3683         const int    numdof=NDOF1*NUMVERTICES;
    3684 
    3685         /*Intermediaries */
    3686         int        i,j,ig;
    3687         int        approximation;
    3688         double     xyz_list[NUMVERTICES][3];
    3689         double     Jdet;
    3690         double     vx,vy,vz,dbdx,dbdy,meltingvalue;
    3691         double     slope[2];
    3692         double     L[NUMVERTICES];
    3693         GaussTria* gauss=NULL;
    3694 
    3695         /*Initialize Element vector and return if necessary*/
    3696         if(IsOnWater()) return NULL;
    3697         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3698 
    3699         /*Retrieve all inputs and parameters*/
    3700         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3701         inputs->GetParameterValue(&approximation,ApproximationEnum);
    3702         Input* bed_input=inputs->GetInput(BedEnum);             ISSMASSERT(bed_input);
    3703         Input* melting_input=inputs->GetInput(MeltingRateEnum); ISSMASSERT(melting_input);
    3704         Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
    3705         Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
    3706         Input* vzstokes_input=NULL;
    3707         if(approximation==PattynStokesApproximationEnum){
    3708                 vzstokes_input=inputs->GetInput(VzStokesEnum);       ISSMASSERT(vzstokes_input);
    3709         }
    3710 
    3711         /* Start  looping on the number of gaussian points: */
    3712         gauss=new GaussTria(2);
    3713         for(ig=gauss->begin();ig<gauss->end();ig++){
    3714 
    3715                 gauss->GaussPoint(ig);
    3716 
    3717                 melting_input->GetParameterValue(&meltingvalue, gauss);
    3718                 bed_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    3719                 vx_input->GetParameterValue(&vx, gauss);
    3720                 vy_input->GetParameterValue(&vy, gauss);
    3721                 if(approximation==PattynStokesApproximationEnum){
    3722                         vzstokes_input->GetParameterValue(&vz, gauss);
    3723                 }
    3724                 else vz=0;
    3725 
    3726                 dbdx=slope[0];
    3727                 dbdy=slope[1];
    3728 
    3729                 GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
    3730                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    3731 
    3732                 for(i=0;i<numdof;i++) pe->values[i]+=-Jdet*gauss->weight*(vx*dbdx+vy*dbdy-vz-meltingvalue)*L[i];
    3733         }
    3734 
    3735         /*Clean up and return*/
    3736         delete gauss;
    3737         return pe;
    3738 }
    3739 /*}}}*/
    3740 /*FUNCTION Tria::CreatePVectorDiagnosticMacAyeal {{{1*/
    3741 ElementVector* Tria::CreatePVectorDiagnosticMacAyeal(){
    3742 
    3743         /*Constants*/
    3744         const int    numdof=NDOF2*NUMVERTICES;
    3745 
    3746         /*Intermediaries */
    3747         int            i,j,ig,drag_type;
    3748         double         plastic_stress,driving_stress_baseline,thickness;
    3749         double         Jdet;
    3750         double         xyz_list[NUMVERTICES][3];
    3751         double         slope[2];
    3752         double         l1l2l3[3];
    3753         double         pe_g_gaussian[numdof];
    3754         GaussTria*     gauss=NULL;
    3755 
    3756         /*Initialize Element vector and return if necessary*/
    3757         if(IsOnWater()) return NULL;
    3758         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
    3759 
    3760         /*Retrieve all inputs and parameters*/
    3761         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3762         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    3763         Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
    3764         Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
    3765         Input* drag_input=inputs->GetInput(DragCoefficientEnum);ISSMASSERT(drag_input);
    3766 
    3767         /* Start  looping on the number of gaussian points: */
    3768         gauss=new GaussTria(2);
    3769         for(ig=gauss->begin();ig<gauss->end();ig++){
    3770 
    3771                 gauss->GaussPoint(ig);
    3772 
    3773                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    3774                 GetNodalFunctions(l1l2l3, gauss);
    3775 
    3776                 thickness_input->GetParameterValue(&thickness,gauss);
    3777                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    3778                
    3779                 /*In case we have plastic basal drag, compute plastic stress at gaussian point from k1, k2 and k3 fields in the
    3780                  * element itself: */
    3781                 if(drag_type==1) drag_input->GetParameterValue(&plastic_stress,gauss);
    3782 
    3783                 driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG()*thickness;
    3784 
    3785                 /*Build pe_g_gaussian vector: */
    3786                 if(drag_type==1){
    3787                         for (i=0;i<NUMVERTICES;i++){
    3788                                 for (j=0;j<NDOF2;j++){
    3789                                         pe->values[i*NDOF2+j]+=(-driving_stress_baseline*slope[j]-plastic_stress)*Jdet*gauss->weight*l1l2l3[i];
    3790                                 }
    3791                         }
    3792                 }
    3793                 else {
    3794                         for (i=0;i<NUMVERTICES;i++){
    3795                                 for (j=0;j<NDOF2;j++){
    3796                                         pe->values[i*NDOF2+j]+=-driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l2l3[i];
    3797                                 }
    3798                         }
    3799                 }
    3800         }
    3801 
    3802         /*Clean up and return*/
    3803         delete gauss;
    3804         return pe;
    3805 }
    3806 /*}}}*/
    3807 /*FUNCTION Tria::CreatePVectorAdjointBalancedthickness{{{1*/
    3808 ElementVector* Tria::CreatePVectorAdjointBalancedthickness(void){
    3809 
    3810         /*Constants*/
    3811         const int    numdof=1*NUMVERTICES;
    3812 
    3813         /*Intermediaries */
    3814         int         i,ig;
    3815         double      Jdet;
    3816         double      thickness,thicknessobs,weight;
    3817         double      xyz_list[NUMVERTICES][3];
    3818         double      l1l2l3[3];
    3819         GaussTria*  gauss=NULL;
    3820 
    3821         /*Initialize Element vector and return if necessary*/
    3822         if(IsOnWater()) return NULL;
    3823         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3824 
    3825         /*Retrieve all inputs and parameters*/
    3826         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3827         Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
    3828         Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
    3829         Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
    3830 
    3831         /* Start  looping on the number of gaussian points: */
    3832         gauss=new GaussTria(2);
    3833         for(ig=gauss->begin();ig<gauss->end();ig++){
    3834 
    3835                 gauss->GaussPoint(ig);
    3836 
    3837                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    3838                 GetNodalFunctions(l1l2l3, gauss);
    3839 
    3840                 thickness_input->GetParameterValue(&thickness, gauss);
    3841                 thicknessobs_input->GetParameterValue(&thicknessobs, gauss);
    3842                 weights_input->GetParameterValue(&weight, gauss);
    3843 
    3844                 for(i=0;i<numdof;i++) pe->values[i]+=(thicknessobs-thickness)*weight*Jdet*gauss->weight*l1l2l3[i];
    3845         }
    3846 
    3847         /*Clean up and return*/
    3848         delete gauss;
    3849         return pe;
    3850 }
    3851 /*}}}*/
    3852 /*FUNCTION Tria::CreatePVectorAdjointHoriz{{{1*/
    3853 ElementVector* Tria::CreatePVectorAdjointHoriz(void){
    3854 
    3855         /*Constants*/
    3856         const int    numdof=NDOF2*NUMVERTICES;
    3857 
    3858         /*Intermediaries */
    3859         int        i,ig,response;
    3860         double     Jdet;
    3861         double     obs_velocity_mag,velocity_mag;
    3862         double     dux,duy,meanvel,epsvel;
    3863         double     scalex=0,scaley=0,scale=0,S=0;
    3864         double     xyz_list[NUMVERTICES][3];
    3865         double     vx_list[NUMVERTICES];
    3866         double     vy_list[NUMVERTICES];
    3867         double     obs_vx_list[NUMVERTICES];
    3868         double     obs_vy_list[NUMVERTICES];
    3869         double     dux_list[NUMVERTICES];
    3870         double     duy_list[NUMVERTICES];
    3871         double     weights_list[NUMVERTICES];
    3872         double     l1l2l3[3];
    3873         GaussTria* gauss=NULL;
    3874 
    3875         /*Initialize Element vector and return if necessary*/
    3876         if(IsOnWater()) return NULL;
    3877         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    3878 
    3879         /*Retrieve all inputs and parameters*/
    3880         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    3881         this->parameters->FindParam(&meanvel,MeanVelEnum);
    3882         this->parameters->FindParam(&epsvel,EpsVelEnum);
    3883         GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
    3884         GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
    3885         GetParameterListOnVertices(&vx_list[0],VxEnum);
    3886         GetParameterListOnVertices(&vy_list[0],VyEnum);
    3887         GetParameterListOnVertices(&weights_list[0],WeightsEnum);
    3888         inputs->GetParameterValue(&response,CmResponseEnum);
    3889         if(response==SurfaceAverageVelMisfitEnum){
    3890                 inputs->GetParameterValue(&S,SurfaceAreaEnum);
    3891         }
    3892 
    3893         /*Get Du at the 3 nodes (integration of the linearized function)
    3894          * Here we integrate linearized functions:
    3895          *               
    3896          * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
    3897          *
    3898          *       d J                  dJ_i
    3899          * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
    3900          *       d u                  du_i
    3901          *
    3902          * where J_i are the misfits at the 3 nodes of the triangle
    3903          *       Phi_i is the nodal function (P1) with respect to
    3904          *       the vertex i
    3905          */
    3906         if(response==SurfaceAbsVelMisfitEnum){
    3907                 /*We are using an absolute misfit:
    3908                  *
    3909                  *      1  [           2              2 ]
    3910                  * J = --- | (u - u   )  +  (v - v   )  |
    3911                  *      2  [       obs            obs   ]
    3912                  *
    3913                  *        dJ
    3914                  * DU = - -- = (u   - u )
    3915                  *        du     obs
    3916                  */
    3917                 for (i=0;i<NUMVERTICES;i++){
    3918                         dux_list[i]=obs_vx_list[i]-vx_list[i];
    3919                         duy_list[i]=obs_vy_list[i]-vy_list[i];
    3920                 }
    3921         }
    3922         else if(response==SurfaceRelVelMisfitEnum){
    3923                 /*We are using a relative misfit:
    3924                  *                       
    3925                  *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
    3926                  * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
    3927                  *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
    3928                  *              obs                        obs                     
    3929                  *
    3930                  *        dJ     \bar{v}^2
    3931                  * DU = - -- = ------------- (u   - u )
    3932                  *        du   (u   + eps)^2    obs
    3933                  *               obs
    3934                  */
    3935                 for (i=0;i<NUMVERTICES;i++){
    3936                         scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
    3937                         scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
    3938                         if(obs_vx_list[i]==0)scalex=0;
    3939                         if(obs_vy_list[i]==0)scaley=0;
    3940                         dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
    3941                         duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
    3942                 }
    3943         }
    3944         else if(response==SurfaceLogVelMisfitEnum){
    3945                 /*We are using a logarithmic misfit:
    3946                  *                       
    3947                  *                 [        vel + eps     ] 2
    3948                  * J = 4 \bar{v}^2 | log ( -----------  ) | 
    3949                  *                 [       vel   + eps    ]
    3950                  *                            obs
    3951                  *
    3952                  *        dJ                 2 * log(...)
    3953                  * DU = - -- = - 4 \bar{v}^2 -------------  u
    3954                  *        du                 vel^2 + eps
    3955                  *           
    3956                  */
    3957                 for (i=0;i<NUMVERTICES;i++){
    3958                         velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
    3959                         obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
    3960                         scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
    3961                         dux_list[i]=scale*vx_list[i];
    3962                         duy_list[i]=scale*vy_list[i];
    3963                 }
    3964         }
    3965         else if(response==SurfaceAverageVelMisfitEnum){
    3966                 /*We are using an spacially average absolute misfit:
    3967                  *
    3968                  *      1                    2              2
    3969                  * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
    3970                  *      S                obs            obs
    3971                  *
    3972                  *        dJ      1       1
    3973                  * DU = - -- = - --- ----------- * 2 (u - u   )
    3974                  *        du      S  2 sqrt(...)           obs
    3975                  */
    3976                 for (i=0;i<NUMVERTICES;i++){
    3977                         scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
    3978                         dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
    3979                         duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
    3980                 }
    3981         }
    3982         else if(response==SurfaceLogVxVyMisfitEnum){
    3983                 /*We are using an logarithmic 2 misfit:
    3984                  *
    3985                  *      1            [        |u| + eps     2          |v| + eps     2  ]
    3986                  * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   | 
    3987                  *      2            [       |u    |+ eps              |v    |+ eps     ]
    3988                  *                              obs                       obs
    3989                  *        dJ                              1      u                             1
    3990                  * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
    3991                  *        du                         |u| + eps  |u|                           u + eps
    3992                  */
    3993                 for (i=0;i<NUMVERTICES;i++){
    3994                         dux_list[i] = - pow(meanvel,(double)2)*(
    3995                                                 log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
    3996                         duy_list[i] = - pow(meanvel,(double)2)*(
    3997                                                 log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
    3998                 }
    3999         }
    4000         else{
    4001                 /*Not supported yet! : */
    4002                 ISSMERROR("response %s not supported yet",EnumToString(response));
    4003         }
    4004 
    4005         /*Apply weights to DU*/
    4006         for (i=0;i<NUMVERTICES;i++){
    4007                 dux_list[i]=weights_list[i]*dux_list[i];
    4008                 duy_list[i]=weights_list[i]*duy_list[i];
    4009         }
    4010 
    4011         /* Start  looping on the number of gaussian points: */
    4012         gauss=new GaussTria(2);
    4013         for(ig=gauss->begin();ig<gauss->end();ig++){
    4014 
    4015                 gauss->GaussPoint(ig);
    4016 
    4017                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    4018                 GetNodalFunctions(l1l2l3, gauss);
    4019 
    4020                 TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
    4021                 TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
    4022 
    4023                 for (i=0;i<NUMVERTICES;i++){
    4024                         pe->values[i*NDOF2+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
    4025                         pe->values[i*NDOF2+1]+=duy*Jdet*gauss->weight*l1l2l3[i];
    4026                 }
    4027         }
    4028 
    4029         /*Clean up and return*/
    4030         delete gauss;
    4031         return pe;
    4032 }
    4033 /*}}}*/
    4034 /*FUNCTION Tria::CreatePVectorAdjointStokes{{{1*/
    4035 ElementVector* Tria::CreatePVectorAdjointStokes(void){
    4036 
    4037         /*Intermediaries */
    4038         int        i,ig;
    4039         int        fit=-1;
    4040         int        response;
    4041         double     Jdet;
    4042         double     obs_velocity_mag,velocity_mag;
    4043         double     dux,duy,meanvel,epsvel;
    4044         double     scalex=0,scaley=0,scale=0,S=0;
    4045         double     xyz_list[NUMVERTICES][3];
    4046         double     vx_list[NUMVERTICES];
    4047         double     vy_list[NUMVERTICES];
    4048         double     obs_vx_list[NUMVERTICES];
    4049         double     obs_vy_list[NUMVERTICES];
    4050         double     dux_list[NUMVERTICES];
    4051         double     duy_list[NUMVERTICES];
    4052         double     weights_list[NUMVERTICES];
    4053         double     l1l2l3[3];
    4054         GaussTria* gauss=NULL;
    4055 
    4056         /*Initialize Element vector and return if necessary*/
    4057         if(IsOnWater()) return NULL;
    4058         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
    4059 
    4060         /*Retrieve all inputs and parameters*/
    4061         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4062         this->parameters->FindParam(&meanvel,MeanVelEnum);
    4063         this->parameters->FindParam(&epsvel,EpsVelEnum);
    4064         GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
    4065         GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
    4066         GetParameterListOnVertices(&vx_list[0],VxEnum);
    4067         GetParameterListOnVertices(&vy_list[0],VyEnum);
    4068         GetParameterListOnVertices(&weights_list[0],WeightsEnum);
    4069         inputs->GetParameterValue(&response,CmResponseEnum);
    4070         if(response==SurfaceAverageVelMisfitEnum){
    4071                 inputs->GetParameterValue(&S,SurfaceAreaEnum);
    4072         }
    4073 
    4074         /*Get Du at the 3 nodes (integration of the linearized function)
    4075          * Here we integrate linearized functions:
    4076          *               
    4077          * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
    4078          *
    4079          *       d J                  dJ_i
    4080          * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
    4081          *       d u                  du_i
    4082          *
    4083          * where J_i are the misfits at the 3 nodes of the triangle
    4084          *       Phi_i is the nodal function (P1) with respect to
    4085          *       the vertex i
    4086          */
    4087         if(response==SurfaceAbsVelMisfitEnum){
    4088                 /*We are using an absolute misfit:
    4089                  *
    4090                  *      1  [           2              2 ]
    4091                  * J = --- | (u - u   )  +  (v - v   )  |
    4092                  *      2  [       obs            obs   ]
    4093                  *
    4094                  *        dJ             2
    4095                  * DU = - -- = (u   - u )
    4096                  *        du     obs
    4097                  */
    4098                 for (i=0;i<NUMVERTICES;i++){
    4099                         dux_list[i]=obs_vx_list[i]-vx_list[i];
    4100                         duy_list[i]=obs_vy_list[i]-vy_list[i];
    4101                 }
    4102         }
    4103         else if(response==SurfaceRelVelMisfitEnum){
    4104                 /*We are using a relative misfit:
    4105                  *                       
    4106                  *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
    4107                  * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
    4108                  *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
    4109                  *              obs                        obs                     
    4110                  *
    4111                  *        dJ     \bar{v}^2
    4112                  * DU = - -- = ------------- (u   - u )
    4113                  *        du   (u   + eps)^2    obs
    4114                  *               obs
    4115                  */
    4116                 for (i=0;i<NUMVERTICES;i++){
    4117                         scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
    4118                         scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
    4119                         if(obs_vx_list[i]==0)scalex=0;
    4120                         if(obs_vy_list[i]==0)scaley=0;
    4121                         dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
    4122                         duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
    4123                 }
    4124         }
    4125         else if(response==SurfaceLogVelMisfitEnum){
    4126                 /*We are using a logarithmic misfit:
    4127                  *                       
    4128                  *                 [        vel + eps     ] 2
    4129                  * J = 4 \bar{v}^2 | log ( -----------  ) | 
    4130                  *                 [       vel   + eps    ]
    4131                  *                            obs
    4132                  *
    4133                  *        dJ                 2 * log(...)
    4134                  * DU = - -- = - 4 \bar{v}^2 -------------  u
    4135                  *        du                 vel^2 + eps
    4136                  *           
    4137                  */
    4138                 for (i=0;i<NUMVERTICES;i++){
    4139                         velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
    4140                         obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
    4141                         scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
    4142                         dux_list[i]=scale*vx_list[i];
    4143                         duy_list[i]=scale*vy_list[i];
    4144                 }
    4145         }
    4146         else if(response==SurfaceAverageVelMisfitEnum){
    4147                 /*We are using an spacially average absolute misfit:
    4148                  *
    4149                  *      1                    2              2
    4150                  * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
    4151                  *      S                obs            obs
    4152                  *
    4153                  *        dJ      1       1
    4154                  * DU = - -- = - --- ----------- * 2 (u - u   )
    4155                  *        du      S  2 sqrt(...)           obs
    4156                  */
    4157                 for (i=0;i<NUMVERTICES;i++){
    4158                         scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
    4159                         dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
    4160                         duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
    4161                 }
    4162         }
    4163         else if(response==SurfaceLogVxVyMisfitEnum){
    4164                 /*We are using an logarithmic 2 misfit:
    4165                  *
    4166                  *      1            [        |u| + eps     2          |v| + eps     2  ]
    4167                  * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   | 
    4168                  *      2            [       |u    |+ eps              |v    |+ eps     ]
    4169                  *                              obs                       obs
    4170                  *        dJ                              1      u                             1
    4171                  * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
    4172                  *        du                         |u| + eps  |u|                           u + eps
    4173                  */
    4174                 for (i=0;i<NUMVERTICES;i++){
    4175                         dux_list[i] = - pow(meanvel,(double)2)*(
    4176                                                 log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
    4177                         duy_list[i] = - pow(meanvel,(double)2)*(
    4178                                                 log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
    4179                 }
    4180         }
    4181         else{
    4182                 /*Not supported yet! : */
    4183                 ISSMERROR("response %s not supported yet",EnumToString(response));
    4184         }
    4185 
    4186         /*Apply weights to DU*/
    4187         for (i=0;i<NUMVERTICES;i++){
    4188                 dux_list[i]=weights_list[i]*dux_list[i];
    4189                 duy_list[i]=weights_list[i]*duy_list[i];
    4190         }
    4191 
    4192         /* Start  looping on the number of gaussian points: */
    4193         gauss=new GaussTria(2);
    4194         for(ig=gauss->begin();ig<gauss->end();ig++){
    4195 
    4196                 gauss->GaussPoint(ig);
    4197 
    4198                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    4199                 GetNodalFunctions(l1l2l3, gauss);
    4200 
    4201                 TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
    4202                 TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
    4203 
    4204                 for (i=0;i<NUMVERTICES;i++){
    4205                         pe->values[i*NDOF4+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
    4206                         pe->values[i*NDOF4+1]+=duy*Jdet*gauss->weight*l1l2l3[i];
    4207                 }
    4208         }
    4209 
    4210         /*Clean up and return*/
    4211         delete gauss;
    4212         return pe;
    4213 }
    4214 /*}}}*/
    4215 /*FUNCTION Tria::CreatePVectorDiagnosticHutter{{{1*/
    4216 ElementVector* Tria::CreatePVectorDiagnosticHutter(void){
    4217 
    4218         /*Intermediaries */
    4219         int        i,connectivity;
    4220         double     constant_part,ub,vb;
    4221         double     rho_ice,gravity,n,B;
    4222         double     slope2,thickness;
    4223         double     slope[2];
    4224         GaussTria* gauss=NULL;
    4225 
    4226         /*Initialize Element vector and return if necessary*/
    4227         if(IsOnWater()) return NULL;
    4228         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4229 
    4230         /*Retrieve all inputs and parameters*/
    4231         rho_ice=matpar->GetRhoIce();
    4232         gravity=matpar->GetG();
    4233         n=matice->GetN();
    4234         B=matice->GetBbar();
    4235         Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
    4236         Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
    4237         Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
    4238 
    4239         /*Spawn 3 sing elements: */
    4240         gauss=new GaussTria();
    4241         for(i=0;i<NUMVERTICES;i++){
    4242 
    4243                 gauss->GaussVertex(i);
    4244 
    4245                 connectivity=nodes[i]->GetConnectivity();
    4246 
    4247                 thickness_input->GetParameterValue(&thickness,gauss);
    4248                 slopex_input->GetParameterValue(&slope[0],gauss);
    4249                 slopey_input->GetParameterValue(&slope[1],gauss);
    4250                 slope2=pow(slope[0],2)+pow(slope[1],2);
    4251 
    4252                 constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
    4253 
    4254                 ub=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[0];
    4255                 vb=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[1];
    4256 
    4257                 pe->values[2*i]  =(ub-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[0])/(double)connectivity;
    4258                 pe->values[2*i+1]=(vb-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[1])/(double)connectivity;
    4259         }
    4260 
    4261         /*Clean up and return*/
    4262         delete gauss;
    4263         return pe;
    4264 }
    4265 /*}}}*/
    4266 /*FUNCTION Tria::CreatePVectorPrognostic{{{1*/
    4267 ElementVector* Tria::CreatePVectorPrognostic(void){
    4268 
    4269         switch(GetElementType()){
    4270                 case P1Enum:
    4271                         return CreatePVectorPrognostic_CG();
    4272                 case P1DGEnum:
    4273                         return CreatePVectorPrognostic_DG();
    4274                 default:
    4275                         ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
    4276         }
    4277 }
    4278 /*}}}*/
    4279 /*FUNCTION Tria::CreatePVectorPrognostic_CG {{{1*/
    4280 ElementVector* Tria::CreatePVectorPrognostic_CG(void){
    4281 
    4282         /*Constants*/
    4283         const int    numdof=NDOF1*NUMVERTICES;
    4284 
    4285         /*Intermediaries */
    4286         int        i,j,ig;
    4287         double     Jdettria,dt;
    4288         double     accumulation_g,melting_g,thickness_g;
    4289         double     xyz_list[NUMVERTICES][3];
    4290         double     L[NUMVERTICES];
    4291         GaussTria* gauss=NULL;
    4292 
    4293         /*Initialize Element vector and return if necessary*/
    4294         if(IsOnWater()) return NULL;
    4295         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4296 
    4297         /*Retrieve all inputs and parameters*/
    4298         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4299         this->parameters->FindParam(&dt,DtEnum);
    4300         Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
    4301         Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
    4302         Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
    4303 
    4304         /* Start  looping on the number of gaussian points: */
    4305         gauss=new GaussTria(2);
    4306         for(ig=gauss->begin();ig<gauss->end();ig++){
    4307 
    4308                 gauss->GaussPoint(ig);
    4309 
    4310                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    4311                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    4312 
    4313                 accumulation_input->GetParameterValue(&accumulation_g,gauss);
    4314                 melting_input->GetParameterValue(&melting_g,gauss);
    4315                 thickness_input->GetParameterValue(&thickness_g,gauss);
    4316 
    4317                 for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
    4318         }
    4319 
    4320         /*Clean up and return*/
    4321         delete gauss;
    4322         return pe;
    4323 }
    4324 /*}}}*/
    4325 /*FUNCTION Tria::CreatePVectorPrognostic_DG {{{1*/
    4326 ElementVector* Tria::CreatePVectorPrognostic_DG(void){
    4327 
    4328         /*Constants*/
    4329         const int    numdof=NDOF1*NUMVERTICES;
    4330 
    4331         /*Intermediaries */
    4332         int        i,j,ig;
    4333         double     Jdettria,dt;
    4334         double     accumulation_g,melting_g,thickness_g;
    4335         double     xyz_list[NUMVERTICES][3];
    4336         double     L[NUMVERTICES];
    4337         GaussTria* gauss=NULL;
    4338 
    4339         /*Initialize Element vector and return if necessary*/
    4340         if(IsOnWater()) return NULL;
    4341         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4342 
    4343         /*Retrieve all inputs and parameters*/
    4344         this->parameters->FindParam(&dt,DtEnum);
    4345         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4346         Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
    4347         Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
    4348         Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
    4349 
    4350         /* Start  looping on the number of gaussian points: */
    4351         gauss=new GaussTria(2);
    4352         for(ig=gauss->begin();ig<gauss->end();ig++){
    4353 
    4354                 gauss->GaussPoint(ig);
    4355 
    4356                 GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
    4357                 GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
    4358 
    4359                 accumulation_input->GetParameterValue(&accumulation_g,gauss);
    4360                 melting_input->GetParameterValue(&melting_g,gauss);
    4361                 thickness_input->GetParameterValue(&thickness_g,gauss);
    4362 
    4363                 for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
    4364         }
    4365 
    4366         /*Clean up and return*/
    4367         delete gauss;
    4368         return pe;
    4369 }
    4370 /*}}}*/
    4371 /*FUNCTION Tria::CreatePVectorSlope {{{1*/
    4372 ElementVector* Tria::CreatePVectorSlope(void){
    4373 
    4374         /*Constants*/
    4375         const int    numdof=NDOF1*NUMVERTICES;
    4376        
    4377         /*Intermediaries */
    4378         int        i,j,ig;
    4379         int        analysis_type;
    4380         double     Jdet;
    4381         double     xyz_list[NUMVERTICES][3];
    4382         double     slope[2];
    4383         double     l1l2l3[3];
    4384         GaussTria* gauss=NULL;
    4385 
    4386         /*Initialize Element vector and return if necessary*/
    4387         if(IsOnWater()) return NULL;
    4388         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4389 
    4390         /*Retrieve all inputs and parameters*/
    4391         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    4392         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4393         Input* slope_input=NULL;
    4394         if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==SurfaceSlopeYAnalysisEnum)){
    4395                 slope_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(slope_input);
    4396         }
    4397         if ( (analysis_type==BedSlopeXAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
    4398                 slope_input=inputs->GetInput(BedEnum);     ISSMASSERT(slope_input);
    4399         }
    4400                
    4401         /* Start  looping on the number of gaussian points: */
    4402         gauss=new GaussTria(2);
    4403         for(ig=gauss->begin();ig<gauss->end();ig++){
    4404 
    4405                 gauss->GaussPoint(ig);
    4406 
    4407                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
    4408                 GetNodalFunctions(l1l2l3, gauss);
    4409 
    4410                 slope_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
    4411 
    4412                 if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==BedSlopeXAnalysisEnum)){
    4413                         for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[0]*l1l2l3[i];
    4414                 }
    4415                 if ( (analysis_type==SurfaceSlopeYAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
    4416                         for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[1]*l1l2l3[i];
    4417                 }
    4418         }
    4419 
    4420         /*Clean up and return*/
    4421         delete gauss;
    4422         return pe;
    4423 }
    4424 /*}}}*/
    4425 /*FUNCTION Tria::CreatePVectorThermalShelf {{{1*/
    4426 ElementVector* Tria::CreatePVectorThermalShelf(void){
    4427        
    4428         /*Constants*/
    4429         const int  numdof=NUMVERTICES*NDOF1;
    4430 
    4431         /*Intermediaries */
    4432         int        i,ig;
    4433         double     Jdet;
    4434         double     mixed_layer_capacity,thermal_exchange_velocity;
    4435         double     rho_ice,rho_water,pressure,dt,scalar_ocean;
    4436         double     meltingpoint,beta,heatcapacity,t_pmp;
    4437         double     xyz_list[NUMVERTICES][3];
    4438         double     l1l2l3[NUMVERTICES];
    4439         GaussTria* gauss=NULL;
    4440 
    4441         /*Initialize Element vector and return if necessary*/
    4442         if(IsOnWater()) return NULL;
    4443         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4444 
    4445         /*Retrieve all inputs and parameters*/
    4446         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4447         mixed_layer_capacity=matpar->GetMixedLayerCapacity();
    4448         thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
    4449         rho_water=matpar->GetRhoWater();
    4450         rho_ice=matpar->GetRhoIce();
    4451         heatcapacity=matpar->GetHeatCapacity();
    4452         beta=matpar->GetBeta();
    4453         meltingpoint=matpar->GetMeltingPoint();
    4454         this->parameters->FindParam(&dt,DtEnum);
    4455         Input* pressure_input=inputs->GetInput(PressureEnum); ISSMASSERT(pressure_input);
    4456 
    4457         /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    4458         gauss=new GaussTria(2);
    4459         for(ig=gauss->begin();ig<gauss->end();ig++){
    4460 
    4461                 gauss->GaussPoint(ig);
    4462 
    4463                 GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
    4464                 GetNodalFunctions(&l1l2l3[0], gauss);
    4465 
    4466                 pressure_input->GetParameterValue(&pressure,gauss);
    4467                 t_pmp=meltingpoint-beta*pressure;
    4468 
    4469                 scalar_ocean=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(t_pmp)/(heatcapacity*rho_ice);
    4470                 if(dt) scalar_ocean=dt*scalar_ocean;
    4471 
    4472                 for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*l1l2l3[i];
    4473         }
    4474 
    4475         /*Clean up and return*/
    4476         delete gauss;
    4477         return pe;
    4478 }
    4479 /*}}}*/
    4480 /*FUNCTION Tria::CreatePVectorThermalSheet {{{1*/
    4481 ElementVector* Tria::CreatePVectorThermalSheet(void){
    4482 
    4483         /*Constants*/
    4484         const int  numdof=NUMVERTICES*NDOF1;
    4485 
    4486         /*Intermediaries */
    4487         int        i,ig;
    4488         int        analysis_type,drag_type;
    4489         double     xyz_list[NUMVERTICES][3];
    4490         double     Jdet,dt;
    4491         double     rho_ice,heatcapacity,geothermalflux_value;
    4492         double     basalfriction,alpha2,vx,vy,pressure;
    4493         double     pressure_list[3];
    4494         double     scalar;
    4495         double     l1l2l3[NUMVERTICES];
    4496         Friction*  friction=NULL;
    4497         GaussTria* gauss=NULL;
    4498 
    4499         /*Initialize Element vector and return if necessary*/
    4500         if(IsOnWater()) return NULL;
    4501         ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
    4502 
    4503         /*Retrieve all inputs and parameters*/
    4504         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4505         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    4506         rho_ice=matpar->GetRhoIce();
    4507         heatcapacity=matpar->GetHeatCapacity();
    4508         this->inputs->GetParameterValue(&dt,DtEnum);
    4509         Input* vx_input=inputs->GetInput(VxEnum);                         ISSMASSERT(vx_input);
    4510         Input* vy_input=inputs->GetInput(VyEnum);                         ISSMASSERT(vy_input);
    4511         Input* vz_input=inputs->GetInput(VzEnum);                         ISSMASSERT(vz_input);
    4512         Input* geothermalflux_input=inputs->GetInput(GeothermalFluxEnum); ISSMASSERT(geothermalflux_input);
    4513 
    4514         /*Build frictoin element, needed later: */
    4515         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    4516         if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
    4517         friction=new Friction("3d",inputs,matpar,analysis_type);
    4518 
    4519         /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    4520         gauss=new GaussTria(2);
    4521         for(ig=gauss->begin();ig<gauss->end();ig++){
    4522 
    4523                 gauss->GaussPoint(ig);
    4524 
    4525                 GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
    4526                 GetNodalFunctions(&l1l2l3[0], gauss);
    4527 
    4528                 geothermalflux_input->GetParameterValue(&geothermalflux_value,gauss);
    4529                 friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
    4530                 vx_input->GetParameterValue(&vx,gauss);
    4531                 vy_input->GetParameterValue(&vy,gauss);
    4532                 basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
    4533                
    4534                 scalar=gauss->weight*Jdet*(basalfriction+geothermalflux_value)/(heatcapacity*rho_ice);
    4535                 if(dt) scalar=dt*scalar;
    4536 
    4537                 for(i=0;i<numdof;i++) pe->values[i]+=scalar*l1l2l3[i];
    4538         }
    4539 
    4540         /*Clean up and return*/
    4541         delete gauss;
    4542         delete friction;
    4543         return pe;
    4544 }
    4545 /*}}}*/
    4546 /*FUNCTION Tria::GetArea {{{1*/
    4547 double Tria::GetArea(void){
    4548 
    4549         double area=0;
    4550         double xyz_list[NUMVERTICES][3];
    4551         double x1,y1,x2,y2,x3,y3;
    4552 
    4553         /*Get xyz list: */
    4554         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4555         x1=xyz_list[0][0]; y1=xyz_list[0][1];
    4556         x2=xyz_list[1][0]; y2=xyz_list[1][1];
    4557         x3=xyz_list[2][0]; y3=xyz_list[2][1];
    4558  
    4559         return (x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
    4560 }
    4561 /*}}}*/
    4562 /*FUNCTION Tria::GetElementType {{{1*/
    4563 int Tria::GetElementType(){
    4564 
    4565         /*return TriaRef field*/
    4566         return this->element_type;
    4567 
    4568 }
    4569 /*}}}*/
    4570 /*FUNCTION Tria::GetDofList {{{1*/
    4571 void  Tria::GetDofList(int** pdoflist, int approximation_enum,int setenum){
    4572 
    4573         int i,j;
    4574         int count=0;
    4575         int numberofdofs=0;
    4576         int* doflist=NULL;
    4577 
    4578         /*First, figure out size of doflist and create it: */
    4579         for(i=0;i<3;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
    4580         doflist=(int*)xmalloc(numberofdofs*sizeof(int));
    4581 
    4582         /*Populate: */
    4583         count=0;
    4584         for(i=0;i<3;i++){
    4585                 nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
    4586                 count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
    4587         }
    4588 
    4589         /*Assign output pointers:*/
    4590         *pdoflist=doflist;
    4591 }
    4592 /*}}}*/
    4593 /*FUNCTION Tria::GetDofList1 {{{1*/
    4594 void  Tria::GetDofList1(int* doflist){
    4595 
    4596         int i;
    4597         for(i=0;i<3;i++) doflist[i]=nodes[i]->GetDofList1();
    4598 
    4599 }
    4600 /*}}}*/
    4601 /*FUNCTION Tria::GetSidList {{{1*/
    4602 void  Tria::GetSidList(int* sidlist){
    4603 
    4604         int i;
    4605         for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
    4606 
    4607 }
    4608 /*}}}*/
    4609 /*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
    4610 void Tria::GetParameterListOnVertices(double* pvalue,int enumtype){
    4611 
    4612         /*Intermediaries*/
    4613         double     value[NUMVERTICES];
    4614         GaussTria *gauss              = NULL;
    4615 
    4616         /*Recover input*/
    4617         Input* input=inputs->GetInput(enumtype);
    4618         if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
    4619 
    4620         /*Checks in debugging mode*/
    4621         ISSMASSERT(pvalue);
    4622 
    4623         /* Start looping on the number of vertices: */
    4624         gauss=new GaussTria();
    4625         for (int iv=0;iv<NUMVERTICES;iv++){
    4626                 gauss->GaussVertex(iv);
    4627                 input->GetParameterValue(&pvalue[iv],gauss);
    4628         }
    4629 
    4630         /*clean-up*/
    4631         delete gauss;
    4632 }
    4633 /*}}}*/
    4634 /*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
    4635 void Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
    4636 
    4637         double     value[NUMVERTICES];
    4638         GaussTria *gauss = NULL;
    4639         Input     *input = inputs->GetInput(enumtype);
    4640 
    4641         /*Checks in debugging mode*/
    4642         ISSMASSERT(pvalue);
    4643 
    4644         /* Start looping on the number of vertices: */
    4645         if (input){
    4646                 gauss=new GaussTria();
    4647                 for (int iv=0;iv<NUMVERTICES;iv++){
    4648                         gauss->GaussVertex(iv);
    4649                         input->GetParameterValue(&pvalue[iv],gauss);
    4650                 }
    4651         }
    4652         else{
    4653                 for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
    4654         }
    4655 
    4656         /*clean-up*/
    4657         delete gauss;
    4658 }
    4659 /*}}}*/
    4660 /*FUNCTION Tria::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
    4661 void Tria::GetParameterValue(double* pvalue,Node* node,int enumtype){
    4662 
    4663         Input* input=inputs->GetInput(enumtype);
    4664         if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
    4665 
    4666         GaussTria* gauss=new GaussTria();
    4667         gauss->GaussVertex(this->GetNodeIndex(node));
    4668 
    4669         input->GetParameterValue(pvalue,gauss);
    4670         delete gauss;
    4671 }
    4672 /*}}}*/
    4673 /*FUNCTION Tria::GetSolutionFromInputsDiagnosticHoriz{{{1*/
    4674 void  Tria::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
    4675 
    4676         const int    numdof=NDOF2*NUMVERTICES;
    4677 
    4678         int          i;
    4679         int*         doflist=NULL;
    4680         double       vx,vy;
    4681         double       values[numdof];
    4682         GaussTria*   gauss=NULL;
    4683 
    4684         /*Get dof list: */
    4685         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4686 
    4687         /*Get inputs*/
    4688         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    4689         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    4690 
    4691         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4692         /*P1 element only for now*/
    4693         gauss=new GaussTria();
    4694         for(i=0;i<NUMVERTICES;i++){
    4695 
    4696                 gauss->GaussVertex(i);
    4697 
    4698                 /*Recover vx and vy*/
    4699                 vx_input->GetParameterValue(&vx,gauss);
    4700                 vy_input->GetParameterValue(&vy,gauss);
    4701                 values[i*NDOF2+0]=vx;
    4702                 values[i*NDOF2+1]=vy;
    4703         }
    4704 
    4705         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4706 
    4707         /*Free ressources:*/
    4708         delete gauss;
    4709         xfree((void**)&doflist);
    4710 }
    4711 /*}}}*/
    4712 /*FUNCTION Tria::GetSolutionFromInputsDiagnosticHutter{{{1*/
    4713 void  Tria::GetSolutionFromInputsDiagnosticHutter(Vec solution){
    4714 
    4715         const int    numdof=NDOF2*NUMVERTICES;
    4716 
    4717         int i,dummy;
    4718         int*         doflist=NULL;
    4719         double       vx,vy;
    4720         double       values[numdof];
    4721         GaussTria*   gauss=NULL;
    4722 
    4723         /*Get dof list: */
    4724         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4725 
    4726         /*Get inputs*/
    4727         Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
    4728         Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
    4729 
    4730         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4731         /*P1 element only for now*/
    4732         gauss=new GaussTria();
    4733         for(i=0;i<NUMVERTICES;i++){
    4734 
    4735                 gauss->GaussVertex(i);
    4736 
    4737                 /*Recover vx and vy*/
    4738                 vx_input->GetParameterValue(&vx,gauss);
    4739                 vy_input->GetParameterValue(&vy,gauss);
    4740                 values[i*NDOF2+0]=vx;
    4741                 values[i*NDOF2+1]=vy;
    4742         }
    4743 
    4744         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    4745 
    4746         /*Free ressources:*/
    4747         delete gauss;
    4748         xfree((void**)&doflist);
    4749 }
    4750 /*}}}*/
    4751 /*FUNCTION Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){{{1*/
    4752 void Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){
    4753         /*Compute the 2d Strain Rate (3 components):
    4754          * epsilon=[exx eyy exy] */
    4755 
    4756         int i;
    4757         double epsilonvx[3];
    4758         double epsilonvy[3];
    4759 
    4760         /*Check that both inputs have been found*/
    4761         if (!vx_input || !vy_input){
    4762                 ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
    4763         }
    4764 
    4765         /*Get strain rate assuming that epsilon has been allocated*/
    4766         vx_input->GetVxStrainRate2d(epsilonvx,xyz_list,gauss);
    4767         vy_input->GetVyStrainRate2d(epsilonvy,xyz_list,gauss);
    4768 
    4769         /*Sum all contributions*/
    4770         for(i=0;i<3;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
    4771 }
    4772 /*}}}*/
    4773 /*FUNCTION Tria::GradjDragStokes {{{1*/
    4774 void  Tria::GradjDragStokes(Vec gradient){
    4775 
    4776         int        i,ig;
    4777         int        drag_type,analysis_type;
    4778         int        doflist1[NUMVERTICES];
    4779         double     bed,thickness,Neff;
    4780         double     lambda,mu,xi,Jdet,vx,vy,vz;
    4781         double     alpha_complement,drag,cm_noisedmp;
    4782         double     surface_normal[3],bed_normal[3];
    4783         double     xyz_list[NUMVERTICES][3];
    4784         double     dh1dh3[NDOF2][NUMVERTICES];
    4785         double     dk[NDOF2];
    4786         double     l1l2l3[3];
    4787         double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
    4788         double     grade_g[NUMVERTICES]={0.0};
    4789         double     grade_g_gaussian[NUMVERTICES];
    4790         Friction*  friction=NULL;
    4791         GaussTria* gauss=NULL;
    4792 
    4793         /*retrive parameters: */
    4794         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    4795 
    4796         /*retrieve inputs :*/
    4797         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    4798         Input* drag_input    =inputs->GetInput(DragCoefficientEnum); ISSMASSERT(drag_input);
    4799         Input* vx_input      =inputs->GetInput(VxEnum);              ISSMASSERT(vx_input);
    4800         Input* vy_input      =inputs->GetInput(VyEnum);              ISSMASSERT(vy_input);
    4801         Input* vz_input      =inputs->GetInput(VzEnum);              ISSMASSERT(vz_input);
    4802         Input* adjointx_input=inputs->GetInput(AdjointxEnum);        ISSMASSERT(adjointx_input);
    4803         Input* adjointy_input=inputs->GetInput(AdjointyEnum);        ISSMASSERT(adjointy_input);
    4804         Input* adjointz_input=inputs->GetInput(AdjointzEnum);        ISSMASSERT(adjointz_input);
    4805 
    4806         /*retrieve some parameters: */
    4807         this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
    4808 
    4809         /*Get out if shelf*/
    4810         if(IsOnShelf())return;
    4811 
    4812         /* Get node coordinates and dof list: */
    4813         GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
    4814         GetDofList1(&doflist1[0]);
    4815 
    4816         /*Build frictoin element, needed later: */
    4817         inputs->GetParameterValue(&drag_type,DragTypeEnum);
    4818         friction=new Friction("2d",inputs,matpar,analysis_type);
    4819 
    4820         /* Start  looping on the number of gaussian points: */
    4821         gauss=new GaussTria(4);
    4822         for(ig=gauss->begin();ig<gauss->end();ig++){
    4823 
    4824                 gauss->GaussPoint(ig);
    4825 
    4826                 /*Recover alpha_complement and drag: */
    4827                 if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
    4828                 else alpha_complement=0;
    4829                 drag_input->GetParameterValue(&drag,gauss);
    4830 
    4831                 /*recover lambda mu and xi: */
    4832                 adjointx_input->GetParameterValue(&lambda,gauss);
    4833                 adjointy_input->GetParameterValue(&mu    ,gauss);
    4834                 adjointz_input->GetParameterValue(&xi    ,gauss);
    4835 
    4836                 /*recover vx vy and vz: */
    4837                 vx_input->GetParameterValue(&vx, gauss);
    4838                 vy_input->GetParameterValue(&vy, gauss);
    4839                 vz_input->GetParameterValue(&vz, gauss);
    4840 
    4841                 /*Get normal vector to the bed */
    4842                 SurfaceNormal(&surface_normal[0],xyz_list);
    4843 
    4844                 bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
    4845                 bed_normal[1]=-surface_normal[1];
    4846                 bed_normal[2]=-surface_normal[2];
    4847 
    4848                 /* Get Jacobian determinant: */
    4849                 GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
    4850 
    4851                 /* Get nodal functions value at gaussian point:*/
    4852                 GetNodalFunctions(l1l2l3, gauss);
    4853 
    4854                 /*Get nodal functions derivatives*/
    4855                 GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
    4856 
    4857                 /*Get k derivative: dk/dx */
    4858                 drag_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
    4859 
    4860                 /*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
    4861                 for (i=0;i<NUMVERTICES;i++){
    4862                         //standard gradient dJ/dki
    4863                         grade_g_gaussian[i]=(
    4864                                                 -lambda*(2*drag*alpha_complement*(vx - vz*bed_normal[0]*bed_normal[2]))
    4865                                                 -mu    *(2*drag*alpha_complement*(vy - vz*bed_normal[1]*bed_normal[2]))
    4866                                                 -xi    *(2*drag*alpha_complement*(-vx*bed_normal[0]*bed_normal[2]-vy*bed_normal[1]*bed_normal[2]))
    4867                                                 )*Jdet*gauss->weight*l1l2l3[i];
    4868 
    4869                         //Add regularization term
    4870                         grade_g_gaussian[i]+= - cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
    4871                 }
    4872 
    4873                 /*Add gradje_g_gaussian vector to gradje_g: */
    4874                 for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
    4875         }
    4876 
    4877         VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
    4878 
    4879         delete friction;
    4880         delete gauss;
    4881 }
    4882 /*}}}*/
    4883 /*FUNCTION Tria::InputUpdateFromSolutionAdjointBalancedthickness {{{1*/
    4884 void  Tria::InputUpdateFromSolutionAdjointBalancedthickness(double* solution){
    4885 
    4886         const int numdof=NDOF1*NUMVERTICES;
    4887 
    4888         int       i;
    4889         int*      doflist=NULL;
    4890         double    values[numdof];
    4891         double    lambda[NUMVERTICES];
    4892 
    4893         /*Get dof list: */
    4894         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4895 
    4896         /*Use the dof list to index into the solution vector: */
    4897         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4898 
    4899         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4900         for(i=0;i<numdof;i++) lambda[i]=values[i];
    4901 
    4902         /*Add vx and vy as inputs to the tria element: */
    4903         this->inputs->AddInput(new TriaVertexInput(AdjointEnum,lambda));
    4904 
    4905         /*Free ressources:*/
    4906         xfree((void**)&doflist);
    4907 }
    4908 /*}}}*/
    4909 /*FUNCTION Tria::InputUpdateFromSolutionAdjointHoriz {{{1*/
    4910 void  Tria::InputUpdateFromSolutionAdjointHoriz(double* solution){
    4911 
    4912         const int numdof=NDOF2*NUMVERTICES;
    4913 
    4914         int       i;
    4915         int*      doflist=NULL;
    4916         double    values[numdof];
    4917         double    lambdax[NUMVERTICES];
    4918         double    lambday[NUMVERTICES];
    4919 
    4920         /*Get dof list: */
    4921         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4922 
    4923         /*Use the dof list to index into the solution vector: */
    4924         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4925 
    4926         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4927         for(i=0;i<NUMVERTICES;i++){
    4928                 lambdax[i]=values[i*NDOF2+0];
    4929                 lambday[i]=values[i*NDOF2+1];
    4930         }
    4931 
    4932         /*Add vx and vy as inputs to the tria element: */
    4933         this->inputs->AddInput(new TriaVertexInput(AdjointxEnum,lambdax));
    4934         this->inputs->AddInput(new TriaVertexInput(AdjointyEnum,lambday));
    4935 
    4936         /*Free ressources:*/
    4937         xfree((void**)&doflist);
    4938 }
    4939 /*}}}*/
    4940 /*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
    4941 void  Tria::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
    4942        
    4943         const int numdof=NDOF2*NUMVERTICES;
    4944 
    4945         int       i;
    4946         int       dummy;
    4947         int*      doflist=NULL;
    4948         double    rho_ice,g;
    4949         double    values[numdof];
    4950         double    vx[NUMVERTICES];
    4951         double    vy[NUMVERTICES];
    4952         double    vz[NUMVERTICES];
    4953         double    vel[NUMVERTICES];
    4954         double    pressure[NUMVERTICES];
    4955         double    thickness[NUMVERTICES];
    4956        
    4957         /*Get dof list: */
    4958         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    4959 
    4960         /*Use the dof list to index into the solution vector: */
    4961         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    4962 
    4963         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    4964         for(i=0;i<NUMVERTICES;i++){
    4965                 vx[i]=values[i*NDOF2+0];
    4966                 vy[i]=values[i*NDOF2+1];
    4967         }
    4968 
    4969         /*Get Vz and compute vel*/
    4970         GetParameterListOnVertices(&vz[0],VzEnum,0);
    4971         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    4972 
    4973         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D,
    4974          *so the pressure is just the pressure at the bedrock: */
    4975         rho_ice=matpar->GetRhoIce();
    4976         g=matpar->GetG();
    4977         GetParameterListOnVertices(&thickness[0],ThicknessEnum);
    4978         for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
    4979 
    4980         /*Now, we have to move the previous Vx and Vy inputs  to old
    4981          * status, otherwise, we'll wipe them off: */
    4982         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    4983         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    4984         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    4985 
    4986         /*Add vx and vy as inputs to the tria element: */
    4987         this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
    4988         this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
    4989         this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
    4990         this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
    4991 
    4992         /*Free ressources:*/
    4993         xfree((void**)&doflist);
    4994 
    4995 }
    4996 /*}}}*/
    4997 /*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHutter {{{1*/
    4998 void  Tria::InputUpdateFromSolutionDiagnosticHutter(double* solution){
    4999        
    5000         const int numdof=NDOF2*NUMVERTICES;
    5001        
    5002         int       i;
    5003         int       dummy;
    5004         int*      doflist=NULL;
    5005         double    rho_ice,g;
    5006         double    values[numdof];
    5007         double    vx[NUMVERTICES];
    5008         double    vy[NUMVERTICES];
    5009         double    vz[NUMVERTICES];
    5010         double    vel[NUMVERTICES];
    5011         double    pressure[NUMVERTICES];
    5012         double    thickness[NUMVERTICES];
    5013         double*   vz_ptr=NULL;
    5014         Input*    vz_input=NULL;
    5015        
    5016         /*Get dof list: */
    5017         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5018 
    5019         /*Use the dof list to index into the solution vector: */
    5020         for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5021 
    5022         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    5023         for(i=0;i<NUMVERTICES;i++){
    5024                 vx[i]=values[i*NDOF2+0];
    5025                 vy[i]=values[i*NDOF2+1];
    5026         }
    5027 
    5028         /*Get Vz*/
    5029         vz_input=inputs->GetInput(VzEnum);
    5030         if (vz_input){
    5031                 if (vz_input->Enum()!=TriaVertexInputEnum){
    5032                         ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
    5033                 }
    5034                 vz_input->GetValuesPtr(&vz_ptr,&dummy);
    5035                 for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
    5036         }
    5037         else{
    5038                 for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
    5039         }
    5040 
    5041         /*Now Compute vel*/
    5042         for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
    5043 
    5044         /*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D,
    5045          *so the pressure is just the pressure at the bedrock: */
    5046         rho_ice=matpar->GetRhoIce();
    5047         g=matpar->GetG();
    5048         GetParameterListOnVertices(&thickness[0],ThicknessEnum);
    5049         for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
    5050 
    5051         /*Now, we have to move the previous Vx and Vy inputs  to old
    5052          * status, otherwise, we'll wipe them off: */
    5053         this->inputs->ChangeEnum(VxEnum,VxOldEnum);
    5054         this->inputs->ChangeEnum(VyEnum,VyOldEnum);
    5055         this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
    5056 
    5057         /*Add vx and vy as inputs to the tria element: */
    5058         this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
    5059         this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
    5060         this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
    5061         this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
    5062 
    5063         /*Free ressources:*/
    5064         xfree((void**)&doflist);
    5065 }
    5066 /*}}}*/
    5067 /*FUNCTION Tria::InputUpdateFromSolutionOneDof{{{1*/
    5068 void  Tria::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
    5069 
    5070         const int numdof          = NDOF1*NUMVERTICES;
    5071 
    5072         int*      doflist=NULL;
    5073         double    values[numdof];
    5074 
    5075         /*Get dof list: */
    5076         GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
    5077 
    5078         /*Use the dof list to index into the solution vector: */
    5079         for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
    5080 
    5081         /*Add input to the element: */
    5082         this->inputs->AddInput(new TriaVertexInput(enum_type,values));
    5083 
    5084         /*Free ressources:*/
    5085         xfree((void**)&doflist);
    5086 }
    5087 /*}}}*/
    5088 /*FUNCTION Tria::IsInput{{{1*/
    5089 bool Tria::IsInput(int name){
    5090         if (
    5091                                 name==ThicknessEnum ||
    5092                                 name==SurfaceEnum ||
    5093                                 name==BedEnum ||
    5094                                 name==SurfaceSlopeXEnum ||
    5095                                 name==SurfaceSlopeYEnum ||
    5096                                 name==MeltingRateEnum ||
    5097                                 name==DtEnum ||
    5098                                 name==AccumulationRateEnum ||
    5099                                 name==SurfaceAreaEnum||
    5100                                 name==VxEnum ||
    5101                                 name==VyEnum ||
    5102                                 name==VxObsEnum ||
    5103                                 name==VyObsEnum ||
    5104                                 name==CmResponseEnum ||
    5105                                 name==DragCoefficientEnum ||
    5106                                 name==GradientEnum ||
    5107                                 name==OldGradientEnum
    5108                 ){
    5109                 return true;
    5110         }
    5111         else return false;
    5112 }
    5113 /*}}}*/
    5114 /*FUNCTION Tria::SetClone {{{1*/
    5115 void  Tria::SetClone(int* minranks){
    5116 
    5117         ISSMERROR("not implemented yet");
    5118 }
    5119 /*}}}1*/
    5120 /*FUNCTION Tria::SurfaceNormal{{{1*/
    5121 void Tria::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
    5122 
    5123         int i;
    5124         double v13[3],v23[3];
    5125         double normal[3];
    5126         double normal_norm;
    5127 
    5128         for (i=0;i<3;i++){
    5129                 v13[i]=xyz_list[0][i]-xyz_list[2][i];
    5130                 v23[i]=xyz_list[1][i]-xyz_list[2][i];
    5131         }
    5132 
    5133         normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
    5134         normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
    5135         normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
    5136 
    5137         normal_norm=sqrt( pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2) );
    5138 
    5139         *(surface_normal)=normal[0]/normal_norm;
    5140         *(surface_normal+1)=normal[1]/normal_norm;
    5141         *(surface_normal+2)=normal[2]/normal_norm;
    5142 }
    5143 /*}}}*/
  • issm/trunk/src/c/objects/Elements/Tria.h

    r6238 r6410  
    166166                void      GetDofList(int** pdoflist,int approximation_enum,int setenum);
    167167                void      GetDofList1(int* doflist);
    168                 void      GetSidList(int* sidlist);
     168                void    GetSidList(int* sidlist);
    169169                void    GetParameterListOnVertices(double* pvalue,int enumtype);
    170170                void    GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue);
Note: See TracChangeset for help on using the changeset viewer.