Changeset 4885


Ignore:
Timestamp:
07/29/10 14:40:49 (15 years ago)
Author:
Mathieu Morlighem
Message:

moved lots of stuff from Penta to PentaRef

Location:
issm/trunk/src/c
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk/src/c/EnumDefinitions/EnumAsString.cpp

    r4873 r4885  
    225225                case P1Enum : return "P1";
    226226                case P1DGEnum : return "P1DG";
     227                case MiniEnum : return "Mini";
    227228                case DoubleElementResultEnum : return "DoubleElementResult";
    228229                case TriaVertexElementResultEnum : return "TriaVertexElementResult";
  • issm/trunk/src/c/EnumDefinitions/EnumDefinitions.h

    r4873 r4885  
    254254        P1Enum,
    255255        P1DGEnum,
     256        MiniEnum,
    256257        /*}}}*/
    257258        /*Results{{{1*/
  • issm/trunk/src/c/EnumDefinitions/StringAsEnum.cpp

    r4873 r4885  
    223223        else if (strcmp(name,"P1")==0) return P1Enum;
    224224        else if (strcmp(name,"P1DG")==0) return P1DGEnum;
     225        else if (strcmp(name,"Mini")==0) return MiniEnum;
    225226        else if (strcmp(name,"DoubleElementResult")==0) return DoubleElementResultEnum;
    226227        else if (strcmp(name,"TriaVertexElementResult")==0) return TriaVertexElementResultEnum;
  • issm/trunk/src/c/objects/Elements/Penta.cpp

    r4882 r4885  
    8888
    8989        penta=new Penta();
     90
     91        //deal with PentaRef mother class
     92        penta->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
     93        for(i=0;i<this->numanalyses;i++) penta->element_type_list[i]=this->element_type_list[i];
    9094
    9195        //deal with PentaHook mother class
     
    161165        /*this time, no need to get enum type, the pointer directly points to the beginning of the
    162166         *object data (thanks to DataSet::Demarshall):*/
    163 
    164167        memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
    165168        memcpy(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
     169
     170        /*demarshall Ref: */
     171        this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
     172        for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
    166173
    167174        /*allocate dynamic memory: */
     
    240247        memcpy(marshalled_dataset,&id,sizeof(id));marshalled_dataset+=sizeof(id);
    241248        memcpy(marshalled_dataset,&numanalyses,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
     249
     250        /*Mershall Ref: */
     251        for(i=0;i<numanalyses;i++){
     252                memcpy(marshalled_dataset,&element_type_list[i],sizeof(element_type_list[i]));marshalled_dataset+=sizeof(element_type_list[i]);
     253        }
    242254
    243255        /*Marshall hooks: */
     
    293305                +hnodes_size
    294306                +sizeof(numanalyses)
     307                +numanalyses*sizeof(int) //element_type_lists
    295308                +hmatice->MarshallSize()
    296309                +hmatpar->MarshallSize()
     
    633646        parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
    634647
     648        /*Get Element type*/
     649        this->element_type=this->element_type_list[analysis_counter];
     650
    635651        /*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective
    636652         * datasets, using internal ids and offsets hidden in hooks: */
     
    641657
    642658        /*Now, go pick up the objects inside the hooks: */
    643         if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
    644         else this->nodes=NULL;
    645         this->matice=(Matice*)this->hmatice->delivers();
    646         this->matpar=(Matpar*)this->hmatpar->delivers();
    647         this->neighbors=(Penta**)this->hneighbors->deliverp();
    648 
    649         /*point parameters to real dataset: */
    650         this->parameters=parametersin;
    651 }
    652 /*}}}*/
    653 /*FUNCTION Penta::SetCurrentConfiguration {{{1*/
    654 void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
    655 
    656         int analysis_counter;
    657        
    658         /*go into parameters and get the analysis_counter: */
    659         parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
    660 
    661         /*Pick up the objects inside the hooks: */
    662659        if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
    663660        else this->nodes=NULL;
     
    958955}
    959956/*}}}*/
    960 /*FUNCTION Penta::GradjDrag {{{1*/
    961 void  Penta::GradjDrag(Vec gradient){
    962 
    963         int i;
    964         Tria* tria=NULL;
    965         TriaVertexInput* triavertexinput=NULL;
    966         double temp_gradient[6]={0,0,0,0,0,0};
    967 
    968         /*inputs: */
    969         bool onwater;
    970         bool onbed;
    971         bool shelf;
    972         int analysis_type;
    973 
    974         /*retrieve parameters: */
    975         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    976 
    977         /*retrieve inputs :*/
    978         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    979         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    980         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    981 
    982         /*If on water, skip: */
    983         if(onwater)return;
    984 
    985         /*If on shelf, skip: */
    986         if(shelf)return;
    987 
    988         /*Bail out if this element does not touch the bedrock: */
    989         if (!onbed) return;
    990 
    991         if (analysis_type==AdjointHorizAnalysisEnum){
    992 
    993                 /*MacAyeal or Pattyn*/
    994                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    995                 tria->GradjDrag(gradient);
    996                 delete tria;
    997         }
    998         else if (analysis_type==AdjointStokesAnalysisEnum){
    999 
    1000                 /*Stokes*/
    1001                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    1002                 tria->GradjDragStokes(gradient);
    1003                 delete tria;
    1004         }
    1005         else ISSMERROR("analysis %s not supported yet",EnumAsString(analysis_type));
    1006 
    1007 
    1008 }
    1009 /*}}}*/
    1010957/*FUNCTION Penta::InputAXPY{{{1*/
    1011958void  Penta::InputAXPY(int YEnum, double scalar, int XEnum){
     
    16921639}
    16931640/*}}}*/
     1641/*FUNCTION Penta::SetCurrentConfiguration {{{1*/
     1642void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
     1643
     1644        int analysis_counter;
     1645
     1646        /*go into parameters and get the analysis_counter: */
     1647        parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
     1648
     1649        /*Get Element type*/
     1650        this->element_type=this->element_type_list[analysis_counter];
     1651
     1652        /*Pick up the objects inside the hooks: */
     1653        if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
     1654        else this->nodes=NULL;
     1655        this->matice=(Matice*)this->hmatice->delivers();
     1656        this->matpar=(Matpar*)this->hmatpar->delivers();
     1657        this->neighbors=(Penta**)this->hneighbors->deliverp();
     1658
     1659        /*point parameters to real dataset: */
     1660        this->parameters=parametersin;
     1661}
     1662/*}}}*/
    16941663/*FUNCTION Penta::SurfaceArea {{{1*/
    16951664double Penta::SurfaceArea(void){
     
    17561725                /*P1 Discontinuous Galerkin*/
    17571726                penta_type=P1DGEnum;
     1727        }
     1728        else if (analysis_type==StokesAnalysisEnum){
     1729                /*MINI Continuous Galerkin*/
     1730                penta_type=MiniEnum;
    17581731        }
    17591732        else{
     
    19681941
    19691942/*Penta specific routines: */
    1970 /*FUNCTION Penta::SpawnTria {{{1*/
    1971 Tria*  Penta::SpawnTria(int g0, int g1, int g2){
     1943/*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
     1944
     1945void  Penta::CreateKMatrixBalancedthickness(Mat Kgg){
     1946
     1947        /*Collapsed formulation: */
     1948        Tria*  tria=NULL;
     1949
     1950        /*flags: */
     1951        bool onwater;
     1952        bool onbed;
     1953
     1954        /*recover some inputs: */
     1955        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     1956        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     1957
     1958        /*If on water, skip: */
     1959        if(onwater)return;
     1960
     1961        /*Is this element on the bed? :*/
     1962        if(!onbed)return;
     1963
     1964        /*Spawn Tria element from the base of the Penta: */
     1965        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1966        tria->CreateKMatrix(Kgg);
     1967        delete tria;
     1968        return;
     1969
     1970}
     1971/*}}}*/
     1972/*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
     1973
     1974void  Penta::CreateKMatrixBalancedvelocities(Mat Kgg){
     1975
     1976        /*Collapsed formulation: */
     1977        Tria*  tria=NULL;
     1978
     1979        /*flags: */
     1980        bool onbed;
     1981        bool onwater;
     1982
     1983        /*recover some inputs: */
     1984        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     1985        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     1986
     1987        /*If on water, skip: */
     1988        if(onwater)return;
     1989
     1990        /*Is this element on the bed? :*/
     1991        if(!onbed)return;
     1992
     1993        /*Spawn Tria element from the base of the Penta: */
     1994        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     1995        tria->CreateKMatrix(Kgg);
     1996        delete tria;
     1997        return;
     1998
     1999}
     2000/*}}}*/
     2001/*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
     2002void Penta::CreateKMatrixDiagnosticHoriz( Mat Kgg){
     2003
     2004        /* local declarations */
     2005        int             i,j;
     2006
     2007        /* node data: */
     2008        const int    numgrids=6;
     2009        const int    numdof=2*numgrids;
     2010        double       xyz_list[numgrids][3];
     2011        int          doflist[numdof];
     2012        int          numberofdofspernode;
     2013
     2014        /* 3d gaussian points: */
     2015        int     num_gauss,ig;
     2016        double* first_gauss_area_coord  =  NULL;
     2017        double* second_gauss_area_coord =  NULL;
     2018        double* third_gauss_area_coord  =  NULL;
     2019        double* fourth_gauss_vert_coord  =  NULL;
     2020        double* area_gauss_weights           =  NULL;
     2021        double* vert_gauss_weights           =  NULL;
     2022        int     ig1,ig2;
     2023        double  gauss_weight1,gauss_weight2;
     2024        double  gauss_coord[4];
     2025        int     order_area_gauss;
     2026        int     num_vert_gauss;
     2027        int     num_area_gauss;
     2028        double  gauss_weight;
     2029
     2030        /* 2d gaussian point: */
     2031        int     num_gauss2d;
     2032        double* first_gauss_area_coord2d  =  NULL;
     2033        double* second_gauss_area_coord2d =  NULL;
     2034        double* third_gauss_area_coord2d  =  NULL;
     2035        double* gauss_weights2d=NULL;
     2036        double  gauss_l1l2l3[3];
     2037
     2038        /* material data: */
     2039        double viscosity; //viscosity
     2040        double oldviscosity; //viscosity
     2041        double newviscosity; //viscosity
     2042
     2043        /* strain rate: */
     2044        double epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
     2045        double oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
     2046
     2047        /* matrices: */
     2048        double B[5][numdof];
     2049        double Bprime[5][numdof];
     2050        double L[2][numdof];
     2051        double D[5][5]={0.0};            // material matrix, simple scalar matrix.
     2052        double D_scalar;
     2053        double DL[2][2]={0.0}; //for basal drag
     2054        double DL_scalar;
     2055
     2056        /* local element matrices: */
     2057        double Ke_gg[numdof][numdof]={0.0}; //local element stiffness matrix
     2058
     2059        double Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
     2060        double Ke_gg_drag_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
     2061        double Jdet;
     2062
     2063        /*slope: */
     2064        double  slope[2]={0.0};
     2065        double  slope_magnitude;
     2066
     2067        /*friction: */
     2068        double  alpha2_list[3];
     2069        double  alpha2;
     2070
     2071        double MAXSLOPE=.06; // 6 %
     2072        double MOUNTAINKEXPONENT=10;
     2073
     2074        /*parameters: */
     2075        double viscosity_overshoot;
     2076
     2077        /*Collapsed formulation: */
     2078        Tria*  tria=NULL;
     2079
     2080        /*inputs: */
     2081        bool onwater;
     2082        bool collapse;
     2083        bool onbed;
     2084        bool shelf;
     2085        Input* vx_input=NULL;
     2086        Input* vy_input=NULL;
     2087        Input* vxold_input=NULL;
     2088        Input* vyold_input=NULL;
     2089
     2090        /*retrieve inputs :*/
     2091        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2092        inputs->GetParameterValue(&collapse,CollapseEnum);
     2093        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2094        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     2095
     2096        /*retrieve some parameters: */
     2097        this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
     2098
     2099        /*If on water, skip stiffness: */
     2100        if(onwater)return;
     2101
     2102        /*Figure out if this pentaelem is collapsed. If so, then bailout, except if it is at the
     2103          bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
     2104          the stiffness matrix. */
     2105
     2106        if ((collapse==1) && (onbed==0)){
     2107                /*This element should be collapsed, but this element is not on the bedrock, therefore all its
     2108                 * dofs have already been frozen! Do nothing: */
     2109                return;
     2110        }
     2111        else if ((collapse==1) && (onbed==1)){
     2112
     2113                /*This element should be collapsed into a tria element at its base. Create this tria element,
     2114                 *and use its CreateKMatrix functionality to fill the global stiffness matrix: */
     2115                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2116                tria->CreateKMatrix(Kgg);
     2117                delete tria;
     2118                return;
     2119        }
     2120        else{
     2121
     2122                /*Implement standard penta element: */
     2123
     2124                /* Get node coordinates and dof list: */
     2125                GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     2126                GetDofList(&doflist[0],&numberofdofspernode);
     2127
     2128                /*Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     2129                  get tria gaussian points as well as segment gaussian points. For tria gaussian
     2130                  points, order of integration is 2, because we need to integrate the product tB*D*B'
     2131                  which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     2132                  points, same deal, which yields 3 gaussian points.*/
     2133
     2134                order_area_gauss=5;
     2135                num_vert_gauss=5;
     2136
     2137                GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
     2138
     2139                /*Retrieve all inputs we will be needing: */
     2140                vx_input=inputs->GetInput(VxEnum);
     2141                vy_input=inputs->GetInput(VyEnum);
     2142                vxold_input=inputs->GetInput(VxOldEnum);
     2143                vyold_input=inputs->GetInput(VyOldEnum);
     2144
     2145                /* Start  looping on the number of gaussian points: */
     2146                for (ig1=0; ig1<num_area_gauss; ig1++){
     2147                        for (ig2=0; ig2<num_vert_gauss; ig2++){
     2148
     2149                                /*Pick up the gaussian point: */
     2150                                gauss_weight1=*(area_gauss_weights+ig1);
     2151                                gauss_weight2=*(vert_gauss_weights+ig2);
     2152                                gauss_weight=gauss_weight1*gauss_weight2;
     2153
     2154
     2155                                gauss_coord[0]=*(first_gauss_area_coord+ig1);
     2156                                gauss_coord[1]=*(second_gauss_area_coord+ig1);
     2157                                gauss_coord[2]=*(third_gauss_area_coord+ig1);
     2158                                gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
     2159
     2160
     2161                                /*Get strain rate from velocity: */
     2162                                this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input);
     2163                                this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss_coord,vxold_input,vyold_input);
     2164
     2165                                /*Get viscosity: */
     2166                                matice->GetViscosity3d(&viscosity, &epsilon[0]);
     2167                                matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
     2168
     2169                                /*Get B and Bprime matrices: */
     2170                                GetBPattyn(&B[0][0], &xyz_list[0][0], gauss_coord);
     2171                                GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss_coord);
     2172
     2173                                /* Get Jacobian determinant: */
     2174                                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     2175
     2176                                /*Build the D matrix: we plug the gaussian weight, the viscosity, and the jacobian determinant
     2177                                  onto this scalar matrix, so that we win some computational time: */
     2178
     2179                                newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
     2180                                D_scalar=newviscosity*gauss_weight*Jdet;
     2181                                for (i=0;i<5;i++){
     2182                                        D[i][i]=D_scalar;
     2183                                }
     2184
     2185                                /*  Do the triple product tB*D*Bprime: */
     2186                                TripleMultiply( &B[0][0],5,numdof,1,
     2187                                                        &D[0][0],5,5,0,
     2188                                                        &Bprime[0][0],5,numdof,0,
     2189                                                        &Ke_gg_gaussian[0][0],0);
     2190
     2191                                /* Add the Ke_gg_gaussian, and optionally Ke_gg_gaussian onto Ke_gg: */
     2192                                for( i=0; i<numdof; i++){
     2193                                        for(j=0;j<numdof;j++){
     2194                                                Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
     2195                                        }
     2196                                }
     2197                        } //for (ig2=0; ig2<num_vert_gauss; ig2++)
     2198                } //for (ig1=0; ig1<num_area_gauss; ig1++)
     2199
     2200
     2201                /*Add Ke_gg to global matrix Kgg: */
     2202                MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
     2203
     2204                //Deal with 2d friction at the bedrock interface
     2205                if((onbed && !shelf)){
     2206
     2207                        /*Build a tria element using the 3 grids of the base of the penta. Then use
     2208                         * the tria functionality to build a friction stiffness matrix on these 3
     2209                         * grids: */
     2210
     2211                        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2212                        tria->CreateKMatrixDiagnosticHorizFriction(Kgg);
     2213                        delete tria;
     2214                }
     2215
     2216        }
     2217
     2218        xfree((void**)&first_gauss_area_coord);
     2219        xfree((void**)&second_gauss_area_coord);
     2220        xfree((void**)&third_gauss_area_coord);
     2221        xfree((void**)&fourth_gauss_vert_coord);
     2222        xfree((void**)&area_gauss_weights);
     2223        xfree((void**)&vert_gauss_weights);
     2224        xfree((void**)&first_gauss_area_coord2d);
     2225        xfree((void**)&second_gauss_area_coord2d);
     2226        xfree((void**)&third_gauss_area_coord2d);
     2227        xfree((void**)&gauss_weights2d);
     2228
     2229}
     2230/*}}}*/
     2231/*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
     2232void  Penta::CreateKMatrixDiagnosticHutter(Mat Kgg){
     2233
     2234        /*Collapsed formulation: */
     2235        Beam*  beam=NULL;
     2236        int    i;
     2237
     2238        /*flags: */
     2239        bool onwater;
     2240
     2241        /*recover some inputs: */
     2242        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2243
     2244        /*If on water, skip: */
     2245        if(onwater)return;
     2246
     2247        /*Spawn 3 beam elements: */
     2248        for(i=0;i<3;i++){
     2249                beam=(Beam*)SpawnBeam(i,i+3); //[0 3], [1 4] and [2 5] are the four vertical edges of the Penta
     2250                beam->CreateKMatrix(Kgg);
     2251        }
     2252
     2253        /*clean up*/
     2254        delete beam;
     2255
     2256}
     2257/*}}}*/
     2258/*FUNCTION Penta::CreateKMatrixDiagnosticStokes {{{1*/
     2259void Penta::CreateKMatrixDiagnosticStokes( Mat Kgg){
     2260
     2261        int i,j;
     2262
     2263        const int numgrids=6;
     2264        const int DOFPERGRID=4;
     2265        const int numdof=numgrids*DOFPERGRID;
     2266        int doflist[numdof];
     2267        int numberofdofspernode;
     2268
     2269        const int numgrids2d=3;
     2270        const int numdof2d=numgrids2d*DOFPERGRID;
     2271
     2272        int   dofs[3]={0,1,2};
     2273
     2274        double K_terms[numdof][numdof]={0.0};
     2275
     2276        /*Material properties: */
     2277        double         gravity,rho_ice,rho_water;
     2278
     2279        /*Collapsed formulation: */
     2280        Tria*  tria=NULL;
     2281
     2282        /*Grid data: */
     2283        double        xyz_list[numgrids][3];
     2284
     2285        /*parameters: */
     2286        double             xyz_list_tria[numgrids2d][3];
     2287        double             surface_normal[3];
     2288        double             bed_normal[3];
     2289        double         thickness;
     2290
     2291        /*matrices: */
     2292        double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble
     2293        double     Ke_reduced[numdof][numdof]; //for the six nodes only
     2294        double     Ke_gaussian[27][27];
     2295        double     Ke_drag_gaussian[numdof2d][numdof2d];
     2296        double     B[8][27];
     2297        double     B_prime[8][27];
     2298        double     LStokes[14][numdof2d];
     2299        double     LprimeStokes[14][numdof2d];
     2300        double     Jdet;
     2301        double     Jdet2d;
     2302        double     D[8][8]={0.0};
     2303        double     D_scalar;
     2304        double     tBD[27][8];
     2305        double     DLStokes[14][14]={0.0};
     2306        double     tLDStokes[numdof2d][14];
     2307
     2308        /* gaussian points: */
     2309        int     num_area_gauss;
     2310        int     igarea,igvert;
     2311        double* first_gauss_area_coord  =  NULL;
     2312        double* second_gauss_area_coord =  NULL;
     2313        double* third_gauss_area_coord  =  NULL;
     2314        double* vert_gauss_coord = NULL;
     2315        double* area_gauss_weights  =  NULL;
     2316        double* vert_gauss_weights  =  NULL;
     2317        double  gaussgrids[numgrids][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     2318
     2319        /* specific gaussian point: */
     2320        double  gauss_weight,area_gauss_weight,vert_gauss_weight;
     2321        double  gauss_coord[4];
     2322        double  gauss_coord_tria[3];
     2323        int area_order=5;
     2324        int     num_vert_gauss=5;
     2325
     2326        double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     2327        double  viscosity;
     2328        double  alpha2_gauss;
     2329        Friction* friction=NULL;
     2330
     2331        /*parameters: */
     2332        double stokesreconditioning;
     2333        int analysis_type;
     2334
     2335        /*inputs: */
     2336        bool onwater;
     2337        bool onbed;
     2338        bool shelf;
     2339        bool isstokes;
     2340
     2341        /*inputs: */
     2342        Input* vx_input=NULL;
     2343        Input* vy_input=NULL;
     2344        Input* vz_input=NULL;
     2345
     2346        /*retrive parameters: */
     2347        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     2348
     2349        /*retrieve inputs :*/
     2350        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2351        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2352        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     2353        inputs->GetParameterValue(&isstokes,IsStokesEnum);
     2354
     2355        /*If on water or not Stokes, skip stiffness: */
     2356        if(onwater || !isstokes) return;
     2357
     2358        /*recovre material parameters: */
     2359        rho_water=matpar->GetRhoWater();
     2360        rho_ice=matpar->GetRhoIce();
     2361        gravity=matpar->GetG();
     2362
     2363        /*retrieve some parameters: */
     2364        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     2365
     2366        /* Get node coordinates and dof list: */
     2367        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     2368        GetDofList(&doflist[0],&numberofdofspernode);
     2369
     2370        /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     2371                get tria gaussian points as well as segment gaussian points. For tria gaussian
     2372                points, order of integration is 2, because we need to integrate the product tB*D*B'
     2373                which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     2374                points, same deal, which yields 3 gaussian points.*/
     2375
     2376        area_order=5;
     2377        num_vert_gauss=5;
     2378
     2379        /* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
     2380        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
     2381
     2382        /*Retrieve all inputs we will be needing: */
     2383        vx_input=inputs->GetInput(VxEnum);
     2384        vy_input=inputs->GetInput(VyEnum);
     2385        vz_input=inputs->GetInput(VzEnum);
     2386
     2387        /* Start  looping on the number of gaussian points: */
     2388        for (igarea=0; igarea<num_area_gauss; igarea++){
     2389                for (igvert=0; igvert<num_vert_gauss; igvert++){
     2390                        /*Pick up the gaussian point: */
     2391                        area_gauss_weight=*(area_gauss_weights+igarea);
     2392                        vert_gauss_weight=*(vert_gauss_weights+igvert);
     2393                        gauss_weight=area_gauss_weight*vert_gauss_weight;
     2394                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     2395                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     2396                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     2397                        gauss_coord[3]=*(vert_gauss_coord+igvert);
     2398
     2399                        /*Compute strain rate: */
     2400                        this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
     2401
     2402                        /*Get viscosity: */
     2403                        matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     2404
     2405                        /*Get B and Bprime matrices: */
     2406                        GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord);
     2407                        GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord);
     2408
     2409                        /* Get Jacobian determinant: */
     2410                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],&gauss_coord[0]);
     2411
     2412                        /* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant
     2413                         * onto this scalar matrix, so that we win some computational time: */
     2414                        D_scalar=gauss_weight*Jdet;
     2415                        for (i=0;i<6;i++){
     2416                                D[i][i]=D_scalar*viscosity;
     2417                        }
     2418                        for (i=6;i<8;i++){
     2419                                D[i][i]=-D_scalar*stokesreconditioning;
     2420                        }
     2421
     2422                        /*  Do the triple product tB*D*Bprime: */
     2423                        MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
     2424                        MatrixMultiply(&tBD[0][0],27,8,0,&B_prime[0][0],8,27,0,&Ke_gaussian[0][0],0);
     2425
     2426                        /*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
     2427                        for(i=0;i<27;i++){
     2428                                for(j=0;j<27;j++){
     2429                                        Ke_temp[i][j]+=Ke_gaussian[i][j];
     2430                                }
     2431                        }
     2432                }
     2433        }
     2434
     2435        if((onbed==1) && (shelf==0)){
     2436
     2437                /*build friction object, used later on: */
     2438                friction=new Friction("3d",inputs,matpar,analysis_type);
     2439
     2440                for(i=0;i<numgrids2d;i++){
     2441                        for(j=0;j<3;j++){
     2442                                xyz_list_tria[i][j]=xyz_list[i][j];
     2443                        }
     2444                }
     2445
     2446                xfree((void**)&first_gauss_area_coord); xfree((void**)&second_gauss_area_coord); xfree((void**)&third_gauss_area_coord); xfree((void**)&area_gauss_weights);
     2447                GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
     2448
     2449                /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     2450                for (igarea=0; igarea<num_area_gauss; igarea++){
     2451                        gauss_weight=*(area_gauss_weights+igarea);
     2452                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     2453                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     2454                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     2455                        gauss_coord[3]=-1;
     2456
     2457                        gauss_coord_tria[0]=*(first_gauss_area_coord+igarea);
     2458                        gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
     2459                        gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
     2460
     2461                        /*Get the Jacobian determinant */
     2462                        tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
     2463
     2464                        /*Get L matrix if viscous basal drag present: */
     2465                        GetLStokes(&LStokes[0][0],  gauss_coord_tria);
     2466                        GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss_coord_tria, gauss_coord);
     2467
     2468                        /*Compute strain rate: */
     2469                        this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
     2470
     2471                        /*Get viscosity at last iteration: */
     2472                        matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     2473
     2474                        /*Get normal vecyor to the bed */
     2475                        SurfaceNormal(&surface_normal[0],xyz_list_tria);
     2476
     2477                        bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
     2478                        bed_normal[1]=-surface_normal[1];
     2479                        bed_normal[2]=-surface_normal[2];
     2480
     2481                        /*Calculate DL on gauss point */
     2482                        friction->GetAlpha2(&alpha2_gauss, gauss_coord,VxEnum,VyEnum,VzEnum);
     2483
     2484                        DLStokes[0][0]=alpha2_gauss*gauss_weight*Jdet2d;
     2485                        DLStokes[1][1]=alpha2_gauss*gauss_weight*Jdet2d;
     2486                        DLStokes[2][2]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
     2487                        DLStokes[3][3]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
     2488                        DLStokes[4][4]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
     2489                        DLStokes[5][5]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
     2490                        DLStokes[6][6]=-viscosity*gauss_weight*Jdet2d*bed_normal[0];
     2491                        DLStokes[7][7]=-viscosity*gauss_weight*Jdet2d*bed_normal[1];
     2492                        DLStokes[8][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[2];
     2493                        DLStokes[9][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[0]/2.0;
     2494                        DLStokes[10][10]=-viscosity*gauss_weight*Jdet2d*bed_normal[1]/2.0;
     2495                        DLStokes[11][11]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[0];
     2496                        DLStokes[12][12]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[1];
     2497                        DLStokes[13][13]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[2];
     2498
     2499                        /*  Do the triple product tL*D*L: */
     2500                        MatrixMultiply(&LStokes[0][0],14,numdof2d,1,&DLStokes[0][0],14,14,0,&tLDStokes[0][0],0);
     2501                        MatrixMultiply(&tLDStokes[0][0],numdof2d,14,0,&LprimeStokes[0][0],14,numdof2d,0,&Ke_drag_gaussian[0][0],0);
     2502
     2503                        for(i=0;i<numdof2d;i++){
     2504                                for(j=0;j<numdof2d;j++){
     2505                                        Ke_temp[i][j]+=Ke_drag_gaussian[i][j];
     2506                                }
     2507                        }
     2508                }
     2509       
     2510                /*Free ressources:*/
     2511                delete friction;
     2512
     2513        } //if ( (onbed==1) && (shelf==0))
     2514
     2515        /*Reduce the matrix */
     2516        ReduceMatrixStokes(&Ke_reduced[0][0], &Ke_temp[0][0]);
     2517
     2518        for(i=0;i<numdof;i++){
     2519                for(j=0;j<numdof;j++){
     2520                        K_terms[i][j]+=Ke_reduced[i][j];
     2521                }
     2522        }
     2523
     2524        /*Add Ke_gg to global matrix Kgg: */
     2525        MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)K_terms,ADD_VALUES);
     2526
     2527
     2528        /*Free ressources:*/
     2529        xfree((void**)&first_gauss_area_coord);
     2530        xfree((void**)&second_gauss_area_coord);
     2531        xfree((void**)&third_gauss_area_coord);
     2532        xfree((void**)&area_gauss_weights);
     2533        xfree((void**)&vert_gauss_coord);
     2534        xfree((void**)&vert_gauss_weights);
     2535
     2536        return;
     2537}
     2538/*}}}*/
     2539/*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
     2540void Penta::CreateKMatrixDiagnosticVert( Mat Kgg){
     2541
     2542        /* local declarations */
     2543        int             i,j;
     2544
     2545        /* node data: */
     2546        const int    numgrids=6;
     2547        const int    NDOF1=1;
     2548        const int    numdof=NDOF1*numgrids;
     2549        double       xyz_list[numgrids][3];
     2550        int          doflist[numdof];
     2551        int          numberofdofspernode;
     2552
     2553        /* 3d gaussian points: */
     2554        int     num_gauss,ig;
     2555        double* first_gauss_area_coord  =  NULL;
     2556        double* second_gauss_area_coord =  NULL;
     2557        double* third_gauss_area_coord  =  NULL;
     2558        double* fourth_gauss_vert_coord  =  NULL;
     2559        double* area_gauss_weights           =  NULL;
     2560        double* vert_gauss_weights           =  NULL;
     2561        int     ig1,ig2;
     2562        double  gauss_weight1,gauss_weight2;
     2563        double  gauss_coord[4];
     2564        int     order_area_gauss;
     2565        int     num_vert_gauss;
     2566        int     num_area_gauss;
     2567        double  gauss_weight;
     2568
     2569        /* matrices: */
     2570        double  Ke_gg[numdof][numdof]={0.0};
     2571        double  Ke_gg_gaussian[numdof][numdof];
     2572        double  Jdet;
     2573        double  B[NDOF1][numgrids];
     2574        double  Bprime[NDOF1][numgrids];
     2575        double  DL_scalar;
     2576
     2577        /*Collapsed formulation: */
     2578        Tria*  tria=NULL;
     2579
     2580        /*inputs: */
     2581        bool onwater;
     2582        bool onsurface;
     2583
     2584        /*retrieve inputs :*/
     2585        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2586        inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
     2587
     2588        /*If on water, skip stiffness: */
     2589        if(onwater)return;
     2590
     2591        /*If this element  is on the surface, we have a dynamic boundary condition that applies, as a stiffness
     2592         * matrix: */
     2593        if(onsurface){
     2594                tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
     2595                tria->CreateKMatrixDiagnosticSurfaceVert(Kgg);
     2596                delete tria;
     2597        }
     2598
     2599        /*Now, onto the formulation for the vertical velocity: */
     2600
     2601        /* Get node coordinates and dof list: */
     2602        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     2603        GetDofList(&doflist[0],&numberofdofspernode);
     2604
     2605        /*Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     2606          get tria gaussian points as well as segment gaussian points. For tria gaussian
     2607          points, order of integration is 2, because we need to integrate the product tB*D*B'
     2608          which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     2609          points, same deal, which yields 3 gaussian points.*/
     2610
     2611        order_area_gauss=2;
     2612        num_vert_gauss=2;
     2613
     2614        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
     2615
     2616        /* Start  looping on the number of gaussian points: */
     2617        for (ig1=0; ig1<num_area_gauss; ig1++){
     2618                for (ig2=0; ig2<num_vert_gauss; ig2++){
     2619
     2620                        /*Pick up the gaussian point: */
     2621                        gauss_weight1=*(area_gauss_weights+ig1);
     2622                        gauss_weight2=*(vert_gauss_weights+ig2);
     2623                        gauss_weight=gauss_weight1*gauss_weight2;
     2624
     2625                        gauss_coord[0]=*(first_gauss_area_coord+ig1);
     2626                        gauss_coord[1]=*(second_gauss_area_coord+ig1);
     2627                        gauss_coord[2]=*(third_gauss_area_coord+ig1);
     2628                        gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
     2629
     2630                        /*Get B and Bprime matrices: */
     2631                        GetBVert(&B[0][0], &xyz_list[0][0], gauss_coord);
     2632                        GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss_coord);
     2633
     2634                        /* Get Jacobian determinant: */
     2635                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     2636                        DL_scalar=gauss_weight*Jdet;
     2637
     2638                        /*  Do the triple product tB*D*Bprime: */
     2639                        TripleMultiply( &B[0][0],1,numgrids,1,
     2640                                                &DL_scalar,1,1,0,
     2641                                                &Bprime[0][0],1,numgrids,0,
     2642                                                &Ke_gg_gaussian[0][0],0);
     2643
     2644                        /* Add the Ke_gg_gaussian, and optionally Ke_gg_drag_gaussian onto Ke_gg: */
     2645                        for( i=0; i<numdof; i++){
     2646                                for(j=0;j<numdof;j++){
     2647                                        Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
     2648                                }
     2649                        }       
     2650                } //for (ig2=0; ig2<num_vert_gauss; ig2++)
     2651        } //for (ig1=0; ig1<num_area_gauss; ig1++)
     2652
     2653        /*Add Ke_gg to global matrix Kgg: */
     2654        MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
     2655
     2656        xfree((void**)&first_gauss_area_coord);
     2657        xfree((void**)&second_gauss_area_coord);
     2658        xfree((void**)&third_gauss_area_coord);
     2659        xfree((void**)&fourth_gauss_vert_coord);
     2660        xfree((void**)&area_gauss_weights);
     2661        xfree((void**)&vert_gauss_weights);
     2662}
     2663/*}}}*/
     2664/*FUNCTION Penta::CreateKMatrixMelting {{{1*/
     2665void  Penta::CreateKMatrixMelting(Mat Kgg){
     2666
     2667        Tria* tria=NULL;
     2668
     2669        /*inputs: */
     2670        bool onwater;
     2671        bool onbed;
     2672
     2673        /*retrieve inputs :*/
     2674        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2675        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2676
     2677        /*If on water, skip: */
     2678        if(onwater)return;
     2679
     2680        if (!onbed){
     2681                return;
     2682        }
     2683        else{
     2684
     2685                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2686                tria->CreateKMatrixMelting(Kgg);
     2687                delete tria;
     2688                return;
     2689        }
     2690}
     2691/*}}}*/
     2692/*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
     2693
     2694void  Penta::CreateKMatrixPrognostic(Mat Kgg){
     2695
     2696        /*Collapsed formulation: */
     2697        Tria*  tria=NULL;
     2698
     2699        /*inputs: */
     2700        bool onwater;
     2701        bool onbed;
     2702
     2703        /*retrieve inputs :*/
     2704        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2705        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2706
     2707        /*If on water, skip: */
     2708        if(onwater)return;
     2709
     2710        /*Is this element on the bed? :*/
     2711        if(!onbed)return;
     2712
     2713        /*Spawn Tria element from the base of the Penta: */
     2714        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2715        tria->CreateKMatrix(Kgg);
     2716        delete tria;
     2717        return;
     2718
     2719}
     2720/*}}}*/
     2721/*FUNCTION Penta::CreateKMatrixSlope {{{1*/
     2722
     2723void  Penta::CreateKMatrixSlope(Mat Kgg){
     2724
     2725        /*Collapsed formulation: */
     2726        Tria*  tria=NULL;
     2727
     2728        /*inputs: */
     2729        bool onwater;
     2730        bool onbed;
     2731
     2732        /*retrieve inputs :*/
     2733        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2734        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2735
     2736
     2737        /*If on water, skip: */
     2738        if(onwater)return;
     2739
     2740        /*Is this element on the bed? :*/
     2741        if(!onbed)return;
     2742
     2743        /*Spawn Tria element from the base of the Penta: */
     2744        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2745        tria->CreateKMatrix(Kgg);
     2746        delete tria;
     2747        return;
     2748
     2749}
     2750/*}}}*/
     2751/*FUNCTION Penta::CreateKMatrixThermal {{{1*/
     2752void  Penta::CreateKMatrixThermal(Mat Kgg){
     2753
     2754        /* local declarations */
     2755        int i,j;
     2756        int found=0;
     2757
     2758        /* node data: */
     2759        const int    numgrids=6;
     2760        const int    NDOF1=1;
     2761        const int    numdof=NDOF1*numgrids;
     2762        double xyz_list[numgrids][3];
     2763        int    doflist[numdof];
     2764        int    numberofdofspernode;
     2765
     2766        /* gaussian points: */
     2767        int     num_area_gauss,igarea,igvert;
     2768        double* first_gauss_area_coord  =  NULL;
     2769        double* second_gauss_area_coord =  NULL;
     2770        double* third_gauss_area_coord  =  NULL;
     2771        double* vert_gauss_coord = NULL;
     2772        double* area_gauss_weights  =  NULL;
     2773        double* vert_gauss_weights  =  NULL;
     2774        double  gauss_weight,area_gauss_weight,vert_gauss_weight;
     2775        double  gauss_coord[4];
     2776        double  gauss_l1l2l3[3];
     2777
     2778        int area_order=5;
     2779        int num_vert_gauss=5;
     2780
     2781        int     dofs[3]={0,1,2};
     2782        double  K[2][2]={0.0};
     2783
     2784        double  u,v,w;
     2785
     2786        /*matrices: */
     2787        double     K_terms[numdof][numdof]={0.0};
     2788        double     Ke_gaussian_conduct[numdof][numdof];
     2789        double     Ke_gaussian_advec[numdof][numdof];
     2790        double     Ke_gaussian_artdiff[numdof][numdof];
     2791        double     Ke_gaussian_transient[numdof][numdof];
     2792        double     B[3][numdof];
     2793        double     Bprime[3][numdof];
     2794        double     B_conduct[3][numdof];
     2795        double     B_advec[3][numdof];
     2796        double     B_artdiff[2][numdof];
     2797        double     Bprime_advec[3][numdof];
     2798        double     L[numdof];
     2799        double     D_scalar;
     2800        double     D[3][3];
     2801        double     l1l2l3[3];
     2802        double     tl1l2l3D[3];
     2803        double     tBD[3][numdof];
     2804        double     tBD_conduct[3][numdof];
     2805        double     tBD_advec[3][numdof];
     2806        double     tBD_artdiff[3][numdof];
     2807        double     tLD[numdof];
     2808
     2809        double     Jdet;
     2810
     2811        /*Material properties: */
     2812        double     gravity,rho_ice,rho_water;
     2813        double     heatcapacity,thermalconductivity;
     2814        double     mixed_layer_capacity,thermal_exchange_velocity;
     2815
     2816        /*parameters: */
     2817        double dt,epsvel;
     2818        bool   artdiff;
     2819
     2820        /*Collapsed formulation: */
     2821        Tria*  tria=NULL;
     2822
     2823
     2824        /*inputs: */
     2825        bool onwater;
     2826        bool onbed;
     2827        bool shelf;
     2828
     2829        /*retrieve inputs :*/
     2830        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     2831        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     2832        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     2833
     2834        /*If on water, skip: */
     2835        if(onwater)return;
     2836
     2837        /* Get node coordinates and dof list: */
     2838        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     2839        GetDofList(&doflist[0],&numberofdofspernode);
     2840
     2841        // /*recovre material parameters: */
     2842        rho_water=matpar->GetRhoWater();
     2843        rho_ice=matpar->GetRhoIce();
     2844        gravity=matpar->GetG();
     2845        heatcapacity=matpar->GetHeatCapacity();
     2846        thermalconductivity=matpar->GetThermalConductivity();
     2847
     2848        /*retrieve some parameters: */
     2849        this->parameters->FindParam(&dt,DtEnum);
     2850        this->parameters->FindParam(&artdiff,ArtDiffEnum);
     2851        this->parameters->FindParam(&epsvel,EpsVelEnum);
     2852
     2853        /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     2854                get tria gaussian points as well as segment gaussian points. For tria gaussian
     2855                points, order of integration is 2, because we need to integrate the product tB*D*B'
     2856                which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     2857                points, same deal, which yields 3 gaussian points.: */
     2858
     2859        /*Get gaussian points: */
     2860        area_order=2;
     2861        num_vert_gauss=2;
     2862
     2863        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
     2864
     2865        /* Start  looping on the number of gaussian points: */
     2866        for (igarea=0; igarea<num_area_gauss; igarea++){
     2867                for (igvert=0; igvert<num_vert_gauss; igvert++){
     2868                        /*Pick up the gaussian point: */
     2869                        area_gauss_weight=*(area_gauss_weights+igarea);
     2870                        vert_gauss_weight=*(vert_gauss_weights+igvert);
     2871                        gauss_weight=area_gauss_weight*vert_gauss_weight;
     2872                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     2873                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     2874                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     2875                        gauss_coord[3]=*(vert_gauss_coord+igvert);
     2876
     2877                        /* Get Jacobian determinant: */
     2878                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     2879
     2880                        /*Conduction: */
     2881
     2882                        /*Get B_conduct matrix: */
     2883                        GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss_coord);
     2884
     2885                        /*Build D: */
     2886                        D_scalar=gauss_weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
     2887
     2888                        if(dt){
     2889                                D_scalar=D_scalar*dt;
     2890                        }
     2891
     2892                        D[0][0]=D_scalar; D[0][1]=0; D[0][2]=0;
     2893                        D[1][0]=0; D[1][1]=D_scalar; D[1][2]=0;
     2894                        D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar;
     2895
     2896                        /*  Do the triple product B'*D*B: */
     2897                        MatrixMultiply(&B_conduct[0][0],3,numdof,1,&D[0][0],3,3,0,&tBD_conduct[0][0],0);
     2898                        MatrixMultiply(&tBD_conduct[0][0],numdof,3,0,&B_conduct[0][0],3,numdof,0,&Ke_gaussian_conduct[0][0],0);
     2899
     2900                        /*Advection: */
     2901
     2902                        /*Get B_advec and Bprime_advec matrices: */
     2903                        GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss_coord);
     2904                        GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss_coord);
     2905
     2906                        //Build the D matrix
     2907                        inputs->GetParameterValue(&u, gauss_coord,VxEnum);
     2908                        inputs->GetParameterValue(&v, gauss_coord,VyEnum);
     2909                        inputs->GetParameterValue(&w, gauss_coord,VzEnum);
     2910
     2911                        D_scalar=gauss_weight*Jdet;
     2912
     2913                        if(dt){
     2914                                D_scalar=D_scalar*dt;
     2915                        }
     2916
     2917                        D[0][0]=D_scalar*u;D[0][1]=0;         D[0][2]=0;
     2918                        D[1][0]=0;         D[1][1]=D_scalar*v;D[1][2]=0;
     2919                        D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar*w;
     2920
     2921                        /*  Do the triple product B'*D*Bprime: */
     2922                        MatrixMultiply(&B_advec[0][0],3,numdof,1,&D[0][0],3,3,0,&tBD_advec[0][0],0);
     2923                        MatrixMultiply(&tBD_advec[0][0],numdof,3,0,&Bprime_advec[0][0],3,numdof,0,&Ke_gaussian_advec[0][0],0);
     2924
     2925                        /*Transient: */
     2926                        if(dt){
     2927                                GetNodalFunctionsP1(&L[0], gauss_coord);
     2928                                D_scalar=gauss_weight*Jdet;
     2929                                D_scalar=D_scalar;
     2930
     2931                                /*  Do the triple product L'*D*L: */
     2932                                MatrixMultiply(&L[0],numdof,1,0,&D_scalar,1,1,0,&tLD[0],0);
     2933                                MatrixMultiply(&tLD[0],numdof,1,0,&L[0],1,numdof,0,&Ke_gaussian_transient[0][0],0);
     2934                        }
     2935                        else{
     2936                                for(i=0;i<numdof;i++){
     2937                                        for(j=0;j<numdof;j++){
     2938                                                Ke_gaussian_transient[i][j]=0;
     2939                                        }
     2940                                }
     2941                        }
     2942
     2943                        /*Artifficial diffusivity*/
     2944                        if(artdiff){
     2945                                /*Build K: */
     2946                                D_scalar=gauss_weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
     2947                                if(dt){
     2948                                        D_scalar=D_scalar*dt;
     2949                                }
     2950                                K[0][0]=D_scalar*pow(u,2);       K[0][1]=D_scalar*fabs(u)*fabs(v);
     2951                                K[1][0]=D_scalar*fabs(u)*fabs(v);K[1][1]=D_scalar*pow(v,2);
     2952
     2953                                /*Get B_artdiff: */
     2954                                GetBArtdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss_coord);
     2955
     2956                                /*  Do the triple product B'*K*B: */
     2957                                MatrixMultiply(&B_artdiff[0][0],2,numdof,1,&K[0][0],2,2,0,&tBD_artdiff[0][0],0);
     2958                                MatrixMultiply(&tBD_artdiff[0][0],numdof,2,0,&B_artdiff[0][0],2,numdof,0,&Ke_gaussian_artdiff[0][0],0);
     2959                        }
     2960                        else{
     2961                                for(i=0;i<numdof;i++){
     2962                                        for(j=0;j<numdof;j++){
     2963                                                Ke_gaussian_artdiff[i][j]=0;
     2964                                        }
     2965                                }
     2966                        }
     2967
     2968                        /*Add Ke_gaussian to pKe: */
     2969                        for(i=0;i<numdof;i++){
     2970                                for(j=0;j<numdof;j++){
     2971                                        K_terms[i][j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
     2972                                }
     2973                        }
     2974                }
     2975        }
     2976
     2977        /*Add Ke_gg to global matrix Kgg: */
     2978        MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)K_terms,ADD_VALUES);
     2979
     2980        xfree((void**)&first_gauss_area_coord);
     2981        xfree((void**)&second_gauss_area_coord);
     2982        xfree((void**)&third_gauss_area_coord);
     2983        xfree((void**)&area_gauss_weights);
     2984        xfree((void**)&vert_gauss_weights);
     2985        xfree((void**)&vert_gauss_coord);
     2986
     2987        //Ice/ocean heat exchange flux on ice shelf base
     2988        if(onbed && shelf){
     2989
     2990                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     2991                tria->CreateKMatrixThermal(Kgg);
     2992                delete tria;
     2993        }
     2994}
     2995/*}}}*/
     2996/*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
     2997void Penta::CreatePVectorBalancedthickness( Vec pg){
     2998
     2999        /*Collapsed formulation: */
     3000        Tria*  tria=NULL;
     3001
     3002        /*flags: */
     3003        bool onbed;
     3004        bool onwater;
     3005
     3006        /*recover some inputs: */
     3007        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3008        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3009
     3010        /*If on water, skip: */
     3011        if(onwater)return;
     3012
     3013        /*Is this element on the bed? :*/
     3014        if(!onbed)return;
     3015
     3016        /*Spawn Tria element from the base of the Penta: */
     3017        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3018        tria->CreatePVector(pg);
     3019        delete tria;
     3020        return;
     3021}
     3022/*}}}*/
     3023/*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
     3024void Penta::CreatePVectorBalancedvelocities( Vec pg){
     3025
     3026        /*Collapsed formulation: */
     3027        Tria*  tria=NULL;
     3028
     3029        /*flags: */
     3030        bool onbed;
     3031        bool onwater;
     3032
     3033        /*recover some inputs: */
     3034        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3035        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3036
     3037        /*If on water, skip: */
     3038        if(onwater)return;
     3039
     3040        /*Is this element on the bed? :*/
     3041        if(!onbed)return;
     3042
     3043        /*Spawn Tria element from the base of the Penta: */
     3044        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3045        tria->CreatePVector(pg);
     3046        delete tria;
     3047        return;
     3048}
     3049/*}}}*/
     3050/*FUNCTION Penta::CreatePVectorDiagnosticHoriz {{{1*/
     3051void Penta::CreatePVectorDiagnosticHoriz( Vec pg){
     3052
     3053        int i,j;
     3054
     3055        /* node data: */
     3056        const int    numgrids=6;
     3057        const int    NDOF2=2;
     3058        const int    numdof=NDOF2*numgrids;
     3059        double       xyz_list[numgrids][3];
     3060        int          doflist[numdof];
     3061        int          numberofdofspernode;
     3062
     3063        /* parameters: */
     3064        double  slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
     3065        double  driving_stress_baseline;
     3066        double  thickness;
     3067
     3068        /* gaussian points: */
     3069        int     num_gauss,ig;
     3070        double* first_gauss_area_coord  =  NULL;
     3071        double* second_gauss_area_coord =  NULL;
     3072        double* third_gauss_area_coord  =  NULL;
     3073        double* fourth_gauss_vert_coord  =  NULL;
     3074        double* area_gauss_weights      =  NULL;
     3075        double* vert_gauss_weights      =  NULL;
     3076        double  gauss_coord[4];
     3077        int     order_area_gauss;
     3078        int     num_vert_gauss;
     3079        int     num_area_gauss;
     3080        int     ig1,ig2;
     3081        double  gauss_weight1,gauss_weight2;
     3082        double  gauss_weight;
     3083
     3084        /* Jacobian: */
     3085        double Jdet;
     3086
     3087        /*nodal functions: */
     3088        double l1l6[6];
     3089
     3090        /*element vector at the gaussian points: */
     3091        double  pe_g[numdof]={0.0};
     3092        double  pe_g_gaussian[numdof];
     3093
     3094        /*Spawning: */
     3095        Tria* tria=NULL;
     3096
     3097        /*inputs: */
     3098        bool onwater;
     3099        bool collapse;
     3100        bool onbed;
     3101        Input* surface_input=NULL;
     3102        Input* thickness_input=NULL;
     3103
     3104        /*retrieve inputs :*/
     3105        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3106        inputs->GetParameterValue(&collapse,CollapseEnum);
     3107        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3108
     3109        /*If on water, skip load: */
     3110        if(onwater)return;
     3111
     3112        /*Figure out if this pentaelem is collapsed. If so, then bailout, except if it is at the
     3113          bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
     3114          the load vector. */
     3115
     3116        if ((collapse==1) && (onbed==0)){
     3117                /*This element should be collapsed, but this element is not on the bedrock, therefore all its
     3118                 * dofs have already been frozen! Do nothing: */
     3119                return;
     3120        }
     3121        else if ((collapse==1) && (onbed==1)){
     3122
     3123                /*This element should be collapsed into a tria element at its base. Create this tria element,
     3124                 *and use its CreatePVector functionality to return an elementary load vector: */
     3125                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3126                tria->CreatePVector(pg);
     3127                delete tria;
     3128                return;
     3129        }
     3130        else{
     3131
     3132                /*Implement standard penta element: */
     3133
     3134                /* Get node coordinates and dof list: */
     3135                GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     3136                GetDofList(&doflist[0],&numberofdofspernode);
     3137
     3138                /*Get gaussian points and weights :*/
     3139                order_area_gauss=2;
     3140                num_vert_gauss=3;
     3141
     3142                GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
     3143
     3144                /*Retrieve all inputs we will be needing: */
     3145                thickness_input=inputs->GetInput(ThicknessEnum);
     3146                surface_input=inputs->GetInput(SurfaceEnum);
     3147
     3148                /* Start  looping on the number of gaussian points: */
     3149                for (ig1=0; ig1<num_area_gauss; ig1++){
     3150                        for (ig2=0; ig2<num_vert_gauss; ig2++){
     3151
     3152                                /*Pick up the gaussian point: */
     3153                                gauss_weight1=*(area_gauss_weights+ig1);
     3154                                gauss_weight2=*(vert_gauss_weights+ig2);
     3155                                gauss_weight=gauss_weight1*gauss_weight2;
     3156
     3157                                gauss_coord[0]=*(first_gauss_area_coord+ig1);
     3158                                gauss_coord[1]=*(second_gauss_area_coord+ig1);
     3159                                gauss_coord[2]=*(third_gauss_area_coord+ig1);
     3160                                gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
     3161
     3162                                /*Compute thickness at gaussian point: */
     3163                                thickness_input->GetParameterValue(&thickness, gauss_coord);
     3164
     3165                                /*Compute slope at gaussian point: */
     3166                                surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss_coord);
     3167
     3168                                /* Get Jacobian determinant: */
     3169                                GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     3170
     3171                                /*Get nodal functions: */
     3172                                GetNodalFunctionsP1(l1l6, gauss_coord);
     3173
     3174                                /*Compute driving stress: */
     3175                                driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
     3176
     3177                                /*Build pe_g_gaussian vector: */
     3178                                for (i=0;i<numgrids;i++){
     3179                                        for (j=0;j<NDOF2;j++){
     3180                                                pe_g_gaussian[i*NDOF2+j]=-driving_stress_baseline*slope[j]*Jdet*gauss_weight*l1l6[i];
     3181                                        }
     3182                                }
     3183
     3184                                /*Add pe_g_gaussian vector to pe_g: */
     3185                                for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
     3186
     3187                        } //for (ig2=0; ig2<num_vert_gauss; ig2++)
     3188                } //for (ig1=0; ig1<num_area_gauss; ig1++)
     3189
     3190        } //else if ((collapse==1) && (onbed==1))
     3191
     3192        /*Add pe_g to global vector pg: */
     3193        VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
     3194
     3195        xfree((void**)&first_gauss_area_coord);
     3196        xfree((void**)&second_gauss_area_coord);
     3197        xfree((void**)&third_gauss_area_coord);
     3198        xfree((void**)&fourth_gauss_vert_coord);
     3199        xfree((void**)&area_gauss_weights);
     3200        xfree((void**)&vert_gauss_weights);
     3201
     3202}
     3203/*}}}*/
     3204/*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
     3205void  Penta::CreatePVectorAdjointHoriz(Vec p_g){
    19723206
    19733207        int i;
    1974         int analysis_counter;
     3208        Tria* tria=NULL;
     3209
     3210        /*inputs: */
     3211        bool onwater;
     3212        bool collapse;
     3213        bool onsurface;
     3214        bool onbed;
     3215
     3216        /*retrieve inputs :*/
     3217        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3218        inputs->GetParameterValue(&collapse,CollapseEnum);
     3219        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3220        inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
     3221
     3222        /*If on water, skip: */
     3223        if(onwater) return;
     3224
     3225        /*Bail out if this element if:
     3226         * -> Non collapsed and not on the surface
     3227         * -> collapsed (2d model) and not on bed) */
     3228        if ((!collapse && !onsurface) || (collapse && !onbed)){
     3229                return;
     3230        }
     3231        else if (collapse){
     3232
     3233                /*This element should be collapsed into a tria element at its base. Create this tria element,
     3234                 * and compute pe_g*/
     3235                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     3236                tria->CreatePVectorAdjointHoriz(p_g);
     3237                delete tria;
     3238                return;
     3239        }
     3240        else{
     3241
     3242                tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     3243                tria->CreatePVectorAdjointHoriz(p_g);
     3244                delete tria;
     3245                return;
     3246        }
     3247}
     3248/*}}}*/
     3249/*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
     3250void  Penta::CreatePVectorDiagnosticHutter(Vec pg){
     3251
     3252        /*Collapsed formulation: */
     3253        Beam*  beam=NULL;
     3254        int    i;
     3255
     3256        /*flags: */
     3257        bool onwater;
     3258
     3259        /*recover some inputs: */
     3260        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3261
     3262        /*If on water, skip: */
     3263        if(onwater)return;
     3264
     3265        /*Spawn 3 beam elements: */
     3266        for(i=0;i<3;i++){
     3267                beam=(Beam*)SpawnBeam(i,i+3); //[0 3], [1 4] and [2 5] are the four vertical edges of the Penta
     3268                beam->CreatePVector(pg);
     3269        }
     3270
     3271        /*clean up*/
     3272        delete beam;
     3273
     3274}
     3275/*}}}*/
     3276/*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
     3277void Penta::CreatePVectorDiagnosticStokes( Vec pg){
     3278
     3279        /*indexing: */
     3280        int i,j;
     3281
     3282        const int numgrids=6;
     3283        const int DOFPERGRID=4;
     3284        const int numdof=numgrids*DOFPERGRID;
     3285        const int numgrids2d=3;
     3286        int numdof2d=numgrids2d*DOFPERGRID;
     3287        int doflist[numdof];
     3288        int numberofdofspernode;
     3289
     3290        /*Material properties: */
     3291        double         gravity,rho_ice,rho_water;
     3292
     3293        /*parameters: */
     3294        double             xyz_list_tria[numgrids2d][3];
     3295        double         xyz_list[numgrids][3];
     3296        double             surface_normal[3];
     3297        double             bed_normal[3];
     3298        double         bed;
     3299
     3300        /* gaussian points: */
     3301        int     num_area_gauss;
     3302        int     igarea,igvert;
     3303        double* first_gauss_area_coord  =  NULL;
     3304        double* second_gauss_area_coord =  NULL;
     3305        double* third_gauss_area_coord  =  NULL;
     3306        double* vert_gauss_coord = NULL;
     3307        double* area_gauss_weights  =  NULL;
     3308        double* vert_gauss_weights  =  NULL;
     3309
     3310        /* specific gaussian point: */
     3311        double  gauss_weight,area_gauss_weight,vert_gauss_weight;
     3312        double  gauss_coord[4];
     3313        double  gauss_coord_tria[3];
     3314
     3315        int     area_order=5;
     3316        int       num_vert_gauss=5;
     3317
     3318        double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
     3319        double  viscosity;
     3320        double  water_pressure;
     3321        int     dofs[3]={0,1,2};
     3322
     3323        /*matrices: */
     3324        double     Pe_temp[27]={0.0}; //for the six nodes and the bubble
     3325        double     Pe_gaussian[27]={0.0}; //for the six nodes and the bubble
     3326        double     Ke_temp[27][3]={0.0}; //for the six nodes and the bubble
     3327        double     Pe_reduced[numdof]; //for the six nodes only
     3328        double     Ke_gaussian[27][3];
     3329        double     L[3]; //for the three nodes of the bed
     3330        double     l1l7[7]; //for the six nodes and the bubble
     3331        double     B[8][27];
     3332        double     B_prime[8][27];
     3333        double     B_prime_bubble[8][3];
     3334        double     Jdet;
     3335        double     Jdet2d;
     3336        double     D[8][8]={0.0};
     3337        double     D_scalar;
     3338        double     tBD[27][8];
     3339        double     P_terms[numdof]={0.0};
     3340
     3341        Tria*            tria=NULL;
     3342
     3343        /*parameters: */
     3344        double stokesreconditioning;
     3345
     3346        /*inputs: */
     3347        bool onwater;
     3348        bool onbed;
     3349        bool shelf;
     3350        bool isstokes;
     3351        Input* vx_input=NULL;
     3352        Input* vy_input=NULL;
     3353        Input* vz_input=NULL;
     3354        Input* bed_input=NULL;
     3355
     3356        /*retrieve inputs :*/
     3357        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3358        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3359        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     3360        inputs->GetParameterValue(&isstokes,IsStokesEnum);
     3361
     3362        /*retrieve some parameters: */
     3363        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     3364
     3365        /*If on water or not Stokes, skip load: */
     3366        if(onwater || !isstokes) return;
     3367
     3368        /*If on water, skip load: */
     3369        if(onwater)return;
     3370
     3371        /*recovre material parameters: */
     3372        rho_water=matpar->GetRhoWater();
     3373        rho_ice=matpar->GetRhoIce();
     3374        gravity=matpar->GetG();
     3375
     3376        /* Get node coordinates and dof list: */
     3377        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     3378        GetDofList(&doflist[0],&numberofdofspernode);
     3379
     3380        /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     3381                get tria gaussian points as well as segment gaussian points. For tria gaussian
     3382                points, order of integration is 2, because we need to integrate the product tB*D*B'
     3383                which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     3384                points, same deal, which yields 3 gaussian points.*/
     3385
     3386        /* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
     3387        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
     3388
     3389        /*Retrieve all inputs we will be needing: */
     3390        vx_input=inputs->GetInput(VxEnum);
     3391        vy_input=inputs->GetInput(VyEnum);
     3392        vz_input=inputs->GetInput(VzEnum);
     3393        bed_input=inputs->GetInput(BedEnum);
     3394
     3395        /* Start  looping on the number of gaussian points: */
     3396        for (igarea=0; igarea<num_area_gauss; igarea++){
     3397                for (igvert=0; igvert<num_vert_gauss; igvert++){
     3398                        /*Pick up the gaussian point: */
     3399                        area_gauss_weight=*(area_gauss_weights+igarea);
     3400                        vert_gauss_weight=*(vert_gauss_weights+igvert);
     3401                        gauss_weight=area_gauss_weight*vert_gauss_weight;
     3402                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     3403                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     3404                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     3405                        gauss_coord[3]=*(vert_gauss_coord+igvert);
     3406
     3407                        /*Compute strain rate and viscosity: */
     3408                        this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
     3409                        matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     3410
     3411                        /* Get Jacobian determinant: */
     3412                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     3413
     3414                        /* Get nodal functions */
     3415                        GetNodalFunctionsMINI(&l1l7[0], gauss_coord);
     3416
     3417                        /* Build gaussian vector */
     3418                        for(i=0;i<numgrids+1;i++){
     3419                                Pe_gaussian[i*DOFPERGRID+2]=-rho_ice*gravity*Jdet*gauss_weight*l1l7[i];
     3420                        }
     3421
     3422                        /*Add Pe_gaussian to terms in Pe_temp. Watch out for column orientation from matlab: */
     3423                        for(i=0;i<27;i++){
     3424                                Pe_temp[i]+=Pe_gaussian[i];
     3425                        }
     3426
     3427                        /*Get B and Bprime matrices: */
     3428                        GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord);
     3429                        GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord);
     3430
     3431                        /*Get bubble part of Bprime */
     3432                        for(i=0;i<8;i++){
     3433                                for(j=0;j<3;j++){
     3434                                        B_prime_bubble[i][j]=B_prime[i][j+24];
     3435                                }
     3436                        }
     3437
     3438                        /* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant
     3439                         * onto this scalar matrix, so that we win some computational time: */
     3440                        D_scalar=gauss_weight*Jdet;
     3441                        for (i=0;i<6;i++){
     3442                                D[i][i]=D_scalar*viscosity;
     3443                        }
     3444                        for (i=6;i<8;i++){
     3445                                D[i][i]=-D_scalar*stokesreconditioning;
     3446                        }
     3447
     3448                        /*  Do the triple product tB*D*Bprime: */
     3449                        MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
     3450                        MatrixMultiply(&tBD[0][0],27,8,0,&B_prime_bubble[0][0],8,3,0,&Ke_gaussian[0][0],0);
     3451
     3452                        /*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
     3453                        for(i=0;i<27;i++){
     3454                                for(j=0;j<3;j++){
     3455                                        Ke_temp[i][j]+=Ke_gaussian[i][j];
     3456                                }
     3457                        }
     3458                }
     3459        }
     3460
     3461        /*Deal with 2d friction at the bedrock interface: */
     3462        if ( (onbed==1) && (shelf==1)){
     3463
     3464                for(i=0;i<numgrids2d;i++){
     3465                        for(j=0;j<3;j++){
     3466                                xyz_list_tria[i][j]=xyz_list[i][j];
     3467                        }
     3468                }
     3469
     3470                xfree((void**)&first_gauss_area_coord); xfree((void**)&second_gauss_area_coord); xfree((void**)&third_gauss_area_coord); xfree((void**)&area_gauss_weights);
     3471                GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
     3472
     3473                /* Start looping on the number of gauss 2d (nodes on the bedrock) */
     3474                for (igarea=0; igarea<num_area_gauss; igarea++){
     3475                        gauss_weight=*(area_gauss_weights+igarea);
     3476                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     3477                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     3478                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     3479                        gauss_coord[3]=-1;
     3480
     3481                        gauss_coord_tria[0]=*(first_gauss_area_coord+igarea);
     3482                        gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
     3483                        gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
     3484
     3485                        /*Get the Jacobian determinant */
     3486                        tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
     3487
     3488                        /* Get bed at gaussian point */
     3489                        bed_input->GetParameterValue(&bed, gauss_coord);
     3490
     3491                        /*Get L matrix : */
     3492                        tria->GetL(&L[0], &xyz_list[0][0], gauss_coord_tria,1);
     3493
     3494                        /*Get water_pressure at gaussian point */
     3495                        water_pressure=gravity*rho_water*bed;
     3496
     3497                        /*Get normal vecyor to the bed */
     3498                        SurfaceNormal(&surface_normal[0],xyz_list_tria);
     3499
     3500                        bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
     3501                        bed_normal[1]=-surface_normal[1];
     3502                        bed_normal[2]=-surface_normal[2];
     3503
     3504                        for(i=0;i<numgrids2d;i++){
     3505                                for(j=0;j<3;j++){
     3506                                        Pe_temp[i*DOFPERGRID+j]+=water_pressure*gauss_weight*Jdet2d*L[i]*bed_normal[j];
     3507                                }
     3508                        }
     3509                }
     3510        } //if ( (onbed==1) && (shelf==1))
     3511
     3512        /*Reduce the matrix */
     3513        ReduceVectorStokes(&Pe_reduced[0], &Ke_temp[0][0], &Pe_temp[0]);
     3514
     3515        for(i=0;i<numdof;i++){
     3516                P_terms[i]+=Pe_reduced[i];
     3517        }
     3518
     3519        /*Add P_terms to global vector pg: */
     3520        VecSetValues(pg,numdof,doflist,(const double*)P_terms,ADD_VALUES);
     3521
     3522        /*Free ressources:*/
     3523        xfree((void**)&first_gauss_area_coord);
     3524        xfree((void**)&second_gauss_area_coord);
     3525        xfree((void**)&third_gauss_area_coord);
     3526        xfree((void**)&area_gauss_weights);
     3527        xfree((void**)&vert_gauss_coord);
     3528        xfree((void**)&vert_gauss_weights);
     3529
     3530}
     3531/*}}}*/
     3532/*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
     3533void  Penta::CreatePVectorAdjointStokes(Vec p_g){
     3534
     3535        int i;
     3536        Tria* tria=NULL;
     3537
     3538        /*inputs: */
     3539        bool onwater;
     3540        bool onsurface;
     3541
     3542        /*retrieve inputs :*/
     3543        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3544        inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
     3545
     3546        /*If on water, skip: */
     3547        if(onwater || !onsurface)return;
     3548
     3549        /*Call Tria's function*/
     3550        tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
     3551        tria->CreatePVectorAdjointStokes(p_g);
     3552        delete tria;
     3553        return;
     3554}
     3555/*}}}*/
     3556/*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
     3557void  Penta::CreatePVectorDiagnosticVert( Vec pg){
     3558
     3559        int i;
     3560
     3561        /* node data: */
     3562        const int    numgrids=6;
     3563        const int    NDOF1=1;
     3564        const int    numdof=NDOF1*numgrids;
     3565        double       xyz_list[numgrids][3];
     3566        int          doflist[numdof];
     3567        int          numberofdofspernode;
     3568
     3569        /* gaussian points: */
     3570        int     num_gauss,ig;
     3571        double* first_gauss_area_coord  =  NULL;
     3572        double* second_gauss_area_coord =  NULL;
     3573        double* third_gauss_area_coord  =  NULL;
     3574        double* fourth_gauss_vert_coord  =  NULL;
     3575        double* area_gauss_weights      =  NULL;
     3576        double* vert_gauss_weights      =  NULL;
     3577        double  gauss_coord[4];
     3578        int     order_area_gauss;
     3579        int     num_vert_gauss;
     3580        int     num_area_gauss;
     3581        int     ig1,ig2;
     3582        double  gauss_weight1,gauss_weight2;
     3583        double  gauss_weight;
     3584
     3585        /* Jacobian: */
     3586        double Jdet;
     3587
     3588        /*element vector at the gaussian points: */
     3589        double  pe_g[numdof]={0.0};
     3590        double  pe_g_gaussian[numdof];
     3591        double l1l6[6];
     3592
     3593        /*Spawning: */
     3594        Tria* tria=NULL;
     3595
     3596        /*input parameters for structural analysis (diagnostic): */
     3597        double du[3];
     3598        double dv[3];
     3599        double dudx,dvdy;
     3600        int     dofs1[1]={0};
     3601        int     dofs2[1]={1};
     3602
     3603        /*inputs: */
     3604        bool onwater;
     3605        bool onbed;
     3606        Input* vx_input=NULL;
     3607        Input* vy_input=NULL;
     3608
     3609        /*retrieve inputs :*/
     3610        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3611        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3612
     3613        /*If on water, skip: */
     3614        if(onwater)return;
     3615
     3616        /*If we are on the bedrock, spawn a tria on the bedrock, and use it to build the
     3617         *diagnostic base vertical stifness: */
     3618        if(onbed){
     3619                tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 are on the bedrock
     3620                tria->CreatePVectorDiagnosticBaseVert(pg);
     3621                delete tria;
     3622        }
     3623
     3624        /*Now, handle the standard penta element: */
     3625        /* Get node coordinates and dof list: */
     3626        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     3627        GetDofList(&doflist[0],&numberofdofspernode);
     3628
     3629        /*Get gaussian points and weights :*/
     3630        order_area_gauss=2;
     3631        num_vert_gauss=2;
     3632
     3633        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
     3634
     3635        /*Retrieve all inputs we will be needing: */
     3636        vx_input=inputs->GetInput(VxEnum);
     3637        vy_input=inputs->GetInput(VyEnum);
     3638
     3639        /* Start  looping on the number of gaussian points: */
     3640        for (ig1=0; ig1<num_area_gauss; ig1++){
     3641                for (ig2=0; ig2<num_vert_gauss; ig2++){
     3642
     3643                        /*Pick up the gaussian point: */
     3644                        gauss_weight1=*(area_gauss_weights+ig1);
     3645                        gauss_weight2=*(vert_gauss_weights+ig2);
     3646                        gauss_weight=gauss_weight1*gauss_weight2;
     3647
     3648                        gauss_coord[0]=*(first_gauss_area_coord+ig1);
     3649                        gauss_coord[1]=*(second_gauss_area_coord+ig1);
     3650                        gauss_coord[2]=*(third_gauss_area_coord+ig1);
     3651                        gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
     3652
     3653                        /*Get velocity derivative, with respect to x and y: */
     3654
     3655                        vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss_coord);
     3656                        vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss_coord);
     3657                        dudx=du[0];
     3658                        dvdy=dv[1];
     3659
     3660                        /* Get Jacobian determinant: */
     3661                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     3662
     3663                        /*Get nodal functions: */
     3664                        GetNodalFunctionsP1(l1l6, gauss_coord);
     3665
     3666                        /*Build pe_g_gaussian vector: */
     3667                        for (i=0;i<numgrids;i++){
     3668                                pe_g_gaussian[i]=(dudx+dvdy)*Jdet*gauss_weight*l1l6[i];
     3669                        }
     3670
     3671                        /*Add pe_g_gaussian vector to pe_g: */
     3672                        for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
     3673
     3674                } //for (ig2=0; ig2<num_vert_gauss; ig2++)
     3675        } //for (ig1=0; ig1<num_area_gauss; ig1++)
     3676
     3677        /*Add pe_g to global vector pg: */
     3678        VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
     3679
     3680        xfree((void**)&first_gauss_area_coord);
     3681        xfree((void**)&second_gauss_area_coord);
     3682        xfree((void**)&third_gauss_area_coord);
     3683        xfree((void**)&fourth_gauss_vert_coord);
     3684        xfree((void**)&area_gauss_weights);
     3685        xfree((void**)&vert_gauss_weights);
     3686}
     3687/*}}}*/
     3688/*FUNCTION Penta::CreatePVectorMelting {{{1*/
     3689void Penta::CreatePVectorMelting( Vec pg){
     3690        return;
     3691}
     3692/*}}}*/
     3693/*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
     3694
     3695void Penta::CreatePVectorPrognostic( Vec pg){
     3696
     3697        /*Collapsed formulation: */
     3698        Tria*  tria=NULL;
     3699
     3700        /*inputs: */
     3701        bool onwater;
     3702        bool onbed;
     3703
     3704        /*retrieve inputs :*/
     3705        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3706        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    19753707       
    1976         /*go into parameters and get the analysis_counter: */
    1977         this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
    1978 
    1979         /*out of grids g0,g1 and g2 from Penta, build a tria element: */
    1980         Tria* tria=NULL;
    1981         int indices[3];
    1982         int zero=0;
    1983         Parameters* tria_parameters=NULL;
    1984         Inputs* tria_inputs=NULL;
    1985         Results* tria_results=NULL;
    1986 
    1987         indices[0]=g0;
    1988         indices[1]=g1;
    1989         indices[2]=g2;
    1990 
    1991         tria_parameters=this->parameters;
    1992         tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
    1993         tria_results=(Results*)this->results->SpawnTriaResults(indices);
    1994        
    1995         tria=new Tria();
    1996         tria->id=this->id;
    1997         tria->inputs=tria_inputs;
    1998         tria->results=tria_results;
    1999         tria->parameters=tria_parameters;
    2000         tria->element_type=P1Enum; //Only P1 CG for now
    2001         this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
    2002 
    2003         /*recover nodes, matice and matpar: */
    2004         tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
    2005         tria->matice=(Matice*)tria->hmatice->delivers();
    2006         tria->matpar=(Matpar*)tria->hmatpar->delivers();
    2007        
    2008         return tria;
    2009 }
    2010 /*}}}*/
    2011 /*FUNCTION Penta::SpawnBeam {{{1*/
    2012 void* Penta::SpawnBeam(int g0, int g1){
    2013 
    2014         int i;
    2015 
    2016         /*out of grids g0,g1 and g2 from Penta, build a beam element: */
    2017         Beam* beam=NULL;
    2018         int indices[2];
    2019         int zero=0;
    2020         Parameters *beam_parameters = NULL;
    2021         Inputs     *beam_inputs     = NULL;
    2022 
    2023         indices[0]=g0;
    2024         indices[1]=g1;
    2025 
    2026         beam_parameters=this->parameters;
    2027         beam_inputs=(Inputs*)this->inputs->SpawnBeamInputs(indices);
    2028 
    2029         beam=new Beam();
    2030         beam->id=this->id;
    2031         beam->inputs=beam_inputs;
    2032         beam->parameters=beam_parameters;
    2033 
    2034         /*now deal with ndoes,matice and matpar: */
    2035         beam->nodes=(Node**)xmalloc(2*sizeof(Node*));
    2036         for(i=0;i<2;i++)beam->nodes[i]=this->nodes[indices[i]];
    2037         beam->matice=this->matice;
    2038         beam->matpar=this->matpar;
    2039 
    2040         return beam;
    2041 }
    2042 /*}}}*/
    2043 /*FUNCTION Penta::SpawnSing {{{1*/
    2044 void* Penta::SpawnSing(int index){
    2045 
    2046         Sing* sing=NULL;
    2047         int zero=0;
    2048         Parameters *sing_parameters = NULL;
    2049         Inputs     *sing_inputs     = NULL;
    2050 
    2051         sing_parameters=this->parameters;
    2052         sing_inputs=(Inputs*)this->inputs->SpawnSingInputs(index);
    2053 
    2054         sing=new Sing();
    2055         sing->id=this->id;
    2056         sing->inputs=sing_inputs;
    2057         sing->parameters=sing_parameters;
    2058 
    2059         /*now deal with nodes,matice and matpar: */
    2060         sing->node=this->nodes[index];
    2061         sing->matice=this->matice;
    2062         sing->matpar=this->matpar;
    2063        
    2064         return sing;
     3708        /*If on water, skip: */
     3709        if(onwater)return;
     3710
     3711        /*Is this element on the bed? :*/
     3712        if(!onbed)return;
     3713
     3714        /*Spawn Tria element from the base of the Penta: */
     3715        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3716        tria->CreatePVector(pg);
     3717        delete tria;
     3718        return;
     3719}
     3720/*}}}*/
     3721/*FUNCTION Penta::CreatePVectorSlope {{{1*/
     3722
     3723void Penta::CreatePVectorSlope( Vec pg){
     3724
     3725        /*Collapsed formulation: */
     3726        Tria*  tria=NULL;
     3727
     3728        /*inputs: */
     3729        bool onwater;
     3730        bool onbed;
     3731
     3732        /*retrieve inputs :*/
     3733        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3734        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3735
     3736        /*If on water, skip: */
     3737        if(onwater)return;
     3738
     3739        /*Is this element on the bed? :*/
     3740        if(!onbed)return;
     3741
     3742        /*Spawn Tria element from the base of the Penta: */
     3743        tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3744        tria->CreatePVector(pg);
     3745        delete tria;
     3746        return;
     3747}
     3748/*}}}*/
     3749/*FUNCTION Penta::CreatePVectorThermal {{{1*/
     3750void Penta::CreatePVectorThermal( Vec pg){
     3751
     3752        /*indexing: */
     3753        int i,j;
     3754        int found=0;
     3755
     3756        const int  numgrids=6;
     3757        const int  NDOF1=1;
     3758        const int  numdof=numgrids*NDOF1;
     3759        int        doflist[numdof];
     3760        int        numberofdofspernode;
     3761
     3762        /*Grid data: */
     3763        double        xyz_list[numgrids][3];
     3764
     3765        /* gaussian points: */
     3766        int     num_area_gauss,igarea,igvert;
     3767        double* first_gauss_area_coord  =  NULL;
     3768        double* second_gauss_area_coord =  NULL;
     3769        double* third_gauss_area_coord  =  NULL;
     3770        double* vert_gauss_coord = NULL;
     3771        double* area_gauss_weights  =  NULL;
     3772        double* vert_gauss_weights  =  NULL;
     3773        double  gauss_weight,area_gauss_weight,vert_gauss_weight;
     3774        double  gauss_coord[4];
     3775        int     area_order=2;
     3776        int       num_vert_gauss=3;
     3777
     3778        double temperature_list[numgrids];
     3779        double temperature;
     3780
     3781        /*Material properties: */
     3782        double gravity,rho_ice,rho_water;
     3783        double mixed_layer_capacity,heatcapacity;
     3784        double beta,meltingpoint,thermal_exchange_velocity;
     3785
     3786        /* element parameters: */
     3787        int    friction_type;
     3788
     3789        int    dofs[3]={0,1,2};
     3790        int    dofs1[1]={0};
     3791
     3792        /*matrices: */
     3793        double P_terms[numdof]={0.0};
     3794        double L[numdof];
     3795        double l1l2l3[3];
     3796        double alpha2_list[3];
     3797        double basalfriction_list[3]={0.0};
     3798        double basalfriction;
     3799        double epsilon[6];
     3800        double epsilon_sqr[3][3];
     3801        double epsilon_matrix[3][3];
     3802
     3803        double Jdet;
     3804        double viscosity;
     3805        double epsilon_eff;
     3806        double phi;
     3807        double t_pmp;
     3808        double scalar;
     3809        double scalar_def;
     3810        double scalar_ocean;
     3811        double scalar_transient;
     3812
     3813        /*Collapsed formulation: */
     3814        Tria*  tria=NULL;
     3815
     3816        /*parameters: */
     3817        double dt;
     3818
     3819        /*inputs: */
     3820        bool onwater;
     3821        bool onbed;
     3822        bool shelf;
     3823        Input* vx_input=NULL;
     3824        Input* vy_input=NULL;
     3825        Input* vz_input=NULL;
     3826
     3827        /*retrieve inputs :*/
     3828        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     3829        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     3830        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     3831
     3832        /*retrieve some parameters: */
     3833        this->parameters->FindParam(&dt,DtEnum);
     3834
     3835        /*If on water, skip: */
     3836        if(onwater)return;
     3837
     3838        /* Get node coordinates and dof list: */
     3839        GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
     3840        GetDofList(&doflist[0],&numberofdofspernode);
     3841
     3842        /*recovre material parameters: */
     3843        rho_water=matpar->GetRhoWater();
     3844        rho_ice=matpar->GetRhoIce();
     3845        gravity=matpar->GetG();
     3846        heatcapacity=matpar->GetHeatCapacity();
     3847        beta=matpar->GetBeta();
     3848        meltingpoint=matpar->GetMeltingPoint();
     3849
     3850        /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
     3851                get tria gaussian points as well as segment gaussian points. For tria gaussian
     3852                points, order of integration is 2, because we need to integrate the product tB*D*B'
     3853                which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
     3854                points, same deal, which yields 3 gaussian points.: */
     3855
     3856        /*Get gaussian points: */
     3857        GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
     3858
     3859        /*Retrieve all inputs we will be needing: */
     3860        vx_input=inputs->GetInput(VxEnum);
     3861        vy_input=inputs->GetInput(VyEnum);
     3862        vz_input=inputs->GetInput(VzEnum);
     3863
     3864        /* Start  looping on the number of gaussian points: */
     3865        for (igarea=0; igarea<num_area_gauss; igarea++){
     3866                for (igvert=0; igvert<num_vert_gauss; igvert++){
     3867                        /*Pick up the gaussian point: */
     3868                        area_gauss_weight=*(area_gauss_weights+igarea);
     3869                        vert_gauss_weight=*(vert_gauss_weights+igvert);
     3870                        gauss_weight=area_gauss_weight*vert_gauss_weight;
     3871                        gauss_coord[0]=*(first_gauss_area_coord+igarea);
     3872                        gauss_coord[1]=*(second_gauss_area_coord+igarea);
     3873                        gauss_coord[2]=*(third_gauss_area_coord+igarea);
     3874                        gauss_coord[3]=*(vert_gauss_coord+igvert);
     3875
     3876                        /*Compute strain rate and viscosity: */
     3877                        this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
     3878                        matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
     3879
     3880                        /* Get Jacobian determinant: */
     3881                        GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
     3882
     3883                        /* Get nodal functions */
     3884                        GetNodalFunctionsP1(&L[0], gauss_coord);
     3885
     3886                        /*Build deformational heating: */
     3887                        GetPhi(&phi, &epsilon[0], viscosity);
     3888
     3889                        /*Build pe_gaussian */
     3890                        scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss_weight;
     3891                        if(dt){
     3892                                scalar_def=scalar_def*dt;
     3893                        }
     3894
     3895                        for(i=0;i<numgrids;i++){
     3896                                P_terms[i]+=scalar_def*L[i];
     3897                        }
     3898
     3899                        /* Build transient now */
     3900                        if(dt){
     3901                                inputs->GetParameterValue(&temperature, gauss_coord,TemperatureEnum);
     3902                                scalar_transient=temperature*Jdet*gauss_weight;
     3903                                for(i=0;i<numgrids;i++){
     3904                                        P_terms[i]+=scalar_transient*L[i];
     3905                                }
     3906                        }
     3907                }
     3908        }
     3909
     3910        /*Add pe_g to global vector pg: */
     3911        VecSetValues(pg,numdof,doflist,(const double*)P_terms,ADD_VALUES);
     3912
     3913        /* Ice/ocean heat exchange flux on ice shelf base */
     3914        if(onbed && shelf){
     3915
     3916                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3917                tria->CreatePVectorThermalShelf(pg);
     3918                delete tria;
     3919        }
     3920
     3921        /* Geothermal flux on ice sheet base and basal friction */
     3922        if(onbed && !shelf){
     3923
     3924                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     3925                tria->CreatePVectorThermalSheet(pg);
     3926                delete tria;
     3927        }
     3928        extern int my_rank;
     3929
     3930        xfree((void**)&first_gauss_area_coord);
     3931        xfree((void**)&second_gauss_area_coord);
     3932        xfree((void**)&third_gauss_area_coord);
     3933        xfree((void**)&vert_gauss_coord);
     3934        xfree((void**)&area_gauss_weights);
     3935        xfree((void**)&vert_gauss_weights);
     3936
    20653937}
    20663938/*}}}*/
     
    21043976}
    21053977/*}}}*/
     3978/*FUNCTION Penta::GetDofList {{{1*/
     3979void  Penta::GetDofList(int* doflist,int* pnumberofdofspernode){
     3980
     3981        int i,j;
     3982        int doflist_per_node[MAXDOFSPERNODE];
     3983        int numberofdofspernode;
     3984
     3985        for(i=0;i<6;i++){
     3986                nodes[i]->GetDofList(&doflist_per_node[0],&numberofdofspernode);
     3987                for(j=0;j<numberofdofspernode;j++){
     3988                        doflist[i*numberofdofspernode+j]=doflist_per_node[j];
     3989                }
     3990        }
     3991
     3992        /*Assign output pointers:*/
     3993        *pnumberofdofspernode=numberofdofspernode;
     3994
     3995}
     3996/*}}}*/
     3997/*FUNCTION Penta::GetDofList1 {{{1*/
     3998void  Penta::GetDofList1(int* doflist){
     3999       
     4000        int i;
     4001
     4002        for(i=0;i<6;i++){
     4003                doflist[i]=nodes[i]->GetDofList1();
     4004        }
     4005
     4006}
     4007/*}}}*/
     4008/*FUNCTION Penta::GetElementType {{{1*/
     4009int Penta::GetElementType(){
     4010
     4011        /*return PentaRef field*/
     4012        return this->element_type;
     4013
     4014}
     4015/*}}}*/
     4016/*FUNCTION Penta::GetMatrixInvert {{{1*/
     4017void Penta::GetMatrixInvert(double*  Ke_invert, double* Ke){
     4018        /*Inverse a 3 by 3 matrix only */
     4019
     4020        double a,b,c,d,e,f,g,h,i;
     4021        double det;
     4022        int calculationdof=3;
     4023
     4024        /*Take the matrix components: */
     4025        a=*(Ke+calculationdof*0+0);
     4026        b=*(Ke+calculationdof*0+1);
     4027        c=*(Ke+calculationdof*0+2);
     4028        d=*(Ke+calculationdof*1+0);
     4029        e=*(Ke+calculationdof*1+1);
     4030        f=*(Ke+calculationdof*1+2);
     4031        g=*(Ke+calculationdof*2+0);
     4032        h=*(Ke+calculationdof*2+1);
     4033        i=*(Ke+calculationdof*2+2);
     4034
     4035        det=a*(e*i-f*h)-b*(d*i-f*g)+c*(d*h-e*g);
     4036
     4037        *(Ke_invert+calculationdof*0+0)=(e*i-f*h)/det;
     4038        *(Ke_invert+calculationdof*0+1)=(c*h-b*i)/det;
     4039        *(Ke_invert+calculationdof*0+2)=(b*f-c*e)/det;
     4040        *(Ke_invert+calculationdof*1+0)=(f*g-d*i)/det;
     4041        *(Ke_invert+calculationdof*1+1)=(a*i-c*g)/det;
     4042        *(Ke_invert+calculationdof*1+2)=(c*d-a*f)/det;
     4043        *(Ke_invert+calculationdof*2+0)=(d*h-e*g)/det;
     4044        *(Ke_invert+calculationdof*2+1)=(b*g-a*h)/det;
     4045        *(Ke_invert+calculationdof*2+2)=(a*e-b*d)/det;
     4046
     4047}
     4048/*}}}*/
     4049/*FUNCTION Penta::GetParameterValue(double* pvalue, double* v_list,double* gauss_coord) {{{1*/
     4050void Penta::GetParameterValue(double* pvalue, double* v_list,double* gauss_coord){
     4051
     4052        const int numgrids=6;
     4053        double l1l6[numgrids];
     4054
     4055        GetNodalFunctionsP1(&l1l6[0], gauss_coord);
     4056
     4057        *pvalue=l1l6[0]*v_list[0]+l1l6[1]*v_list[1]+l1l6[2]*v_list[2]+l1l6[3]*v_list[3]+l1l6[4]*v_list[4]+l1l6[5]*v_list[5];
     4058}
     4059/*}}}*/
     4060/*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node1,Node* node2,double gauss_seg,int enumtype) {{{1*/
     4061void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
     4062
     4063        /*Output*/
     4064        double value;
     4065
     4066        /*Intermediaries*/
     4067        const int numnodes=6;
     4068        int       grid=-1;
     4069        int       i;
     4070        double gauss[numnodes][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4071
     4072        /*go through 3 nodes (all nodes for tria) and identify 1st and 2nd nodes: */
     4073        ISSMASSERT(nodes);
     4074        for(i=0;i<numnodes;i++){
     4075                if (node==nodes[i]){
     4076                        grid=i;
     4077                        break;
     4078                }
     4079        }
     4080
     4081        /*Check that the node has been found*/
     4082        if (grid==-1) ISSMERROR("Node pointer not found in Penta's nodes");
     4083
     4084        /*Get Parameter value on node*/
     4085        inputs->GetParameterValue(pvalue,&gauss[grid][0],enumtype);
     4086        return;
     4087
     4088}
     4089/*}}}*/
     4090/*FUNCTION Penta::GetPhi {{{1*/
     4091void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
     4092        /*Compute deformational heating from epsilon and viscosity */
     4093
     4094        double epsilon_matrix[3][3];
     4095        double epsilon_eff;
     4096        double epsilon_sqr[3][3];
     4097
     4098        /* Build epsilon matrix */
     4099        epsilon_matrix[0][0]=*(epsilon+0);
     4100        epsilon_matrix[1][0]=*(epsilon+3);
     4101        epsilon_matrix[2][0]=*(epsilon+4);
     4102        epsilon_matrix[0][1]=*(epsilon+3);
     4103        epsilon_matrix[1][1]=*(epsilon+1);
     4104        epsilon_matrix[2][1]=*(epsilon+5);
     4105        epsilon_matrix[0][2]=*(epsilon+4);
     4106        epsilon_matrix[1][2]=*(epsilon+5);
     4107        epsilon_matrix[2][2]=*(epsilon+2);
     4108
     4109        /* Effective value of epsilon_matrix */
     4110        epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
     4111        epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
     4112        epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
     4113        epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
     4114        epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
     4115        epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
     4116        epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
     4117        epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
     4118        epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
     4119
     4120        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);
     4121        *phi=2*pow(epsilon_eff,2.0)*viscosity;
     4122}
     4123/*}}}*/
     4124/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
     4125void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
     4126
     4127        int i;
     4128
     4129        const int    numvertices=6;
     4130        const int    numdofpervertex=2;
     4131        const int    numdof=numdofpervertex*numvertices;
     4132        double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4133
     4134        int          doflist[numdof];
     4135        double       values[numdof];
     4136        double       vx;
     4137        double       vy;
     4138
     4139        int          dummy;
     4140
     4141        /*Get dof list: */
     4142        GetDofList(&doflist[0],&dummy);
     4143
     4144        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4145        /*P1 element only for now*/
     4146        for(i=0;i<numvertices;i++){
     4147
     4148                /*Recover vx and vy*/
     4149                inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
     4150                inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
     4151                values[i*numdofpervertex+0]=vx;
     4152                values[i*numdofpervertex+1]=vy;
     4153        }
     4154
     4155        /*Add value to global vector*/
     4156        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     4157
     4158}
     4159/*}}}*/
     4160/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
     4161void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
     4162
     4163        int i;
     4164
     4165        const int    numvertices=6;
     4166        const int    numdofpervertex=2;
     4167        const int    numdof=numdofpervertex*numvertices;
     4168        double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4169
     4170        int          doflist[numdof];
     4171        double       values[numdof];
     4172        double       vx;
     4173        double       vy;
     4174
     4175        int          dummy;
     4176
     4177        /*Get dof list: */
     4178        GetDofList(&doflist[0],&dummy);
     4179
     4180        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4181        /*P1 element only for now*/
     4182        for(i=0;i<numvertices;i++){
     4183
     4184                /*Recover vx and vy*/
     4185                inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
     4186                inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
     4187                values[i*numdofpervertex+0]=vx;
     4188                values[i*numdofpervertex+1]=vy;
     4189        }
     4190
     4191        /*Add value to global vector*/
     4192        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     4193
     4194}
     4195/*}}}*/
     4196/*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
     4197void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
     4198
     4199        int i;
     4200
     4201        const int    numvertices=6;
     4202        const int    numdofpervertex=1;
     4203        const int    numdof=numdofpervertex*numvertices;
     4204        double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4205
     4206        int          doflist[numdof];
     4207        double       values[numdof];
     4208        double       vz;
     4209
     4210        int          dummy;
     4211
     4212        /*Get dof list: */
     4213        GetDofList(&doflist[0],&dummy);
     4214
     4215        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4216        /*P1 element only for now*/
     4217        for(i=0;i<numvertices;i++){
     4218
     4219                /*Recover vz */
     4220                inputs->GetParameterValue(&vz,&gauss[i][0],VxEnum);
     4221                values[i]=vz;
     4222        }
     4223
     4224        /*Add value to global vector*/
     4225        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     4226}
     4227/*}}}*/
     4228/*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
     4229void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
     4230
     4231        int i;
     4232
     4233        const int    numvertices=6;
     4234        const int    numdofpervertex=4;
     4235        const int    numdof=numdofpervertex*numvertices;
     4236        double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4237
     4238        int          doflist[numdof];
     4239        double       values[numdof];
     4240        double       vx,vy,vz,p;
     4241
     4242        int          dummy;
     4243        double       stokesreconditioning;
     4244
     4245        /*Get dof list: */
     4246        GetDofList(&doflist[0],&dummy);
     4247
     4248        /*Recondition pressure: */
     4249        this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
     4250
     4251        /*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
     4252        /*P1 element only for now*/
     4253        for(i=0;i<numvertices;i++){
     4254
     4255                /*Recover vx and vy*/
     4256                inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
     4257                inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
     4258                inputs->GetParameterValue(&vz,&gauss[i][0],VzEnum);
     4259                inputs->GetParameterValue(&p ,&gauss[i][0],PressureEnum);
     4260                values[i*numdofpervertex+0]=vx;
     4261                values[i*numdofpervertex+1]=vy;
     4262                values[i*numdofpervertex+2]=vz;
     4263                values[i*numdofpervertex+3]=p/stokesreconditioning;
     4264        }
     4265
     4266        /*Add value to global vector*/
     4267        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     4268
     4269}
     4270/*}}}*/
     4271/*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
     4272void  Penta::GetSolutionFromInputsThermal(Vec solution){
     4273
     4274        int i;
     4275
     4276        const int    numvertices=6;
     4277        const int    numdofpervertex=1;
     4278        const int    numdof=numdofpervertex*numvertices;
     4279        double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
     4280
     4281        int          doflist[numdof];
     4282        double       values[numdof];
     4283        double       vz;
     4284
     4285        int          dummy;
     4286
     4287        /*Get dof list: */
     4288        GetDofList(&doflist[0],&dummy);
     4289
     4290        /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
     4291        /*P1 element only for now*/
     4292        for(i=0;i<numvertices;i++){
     4293
     4294                /*Recover vz */
     4295                inputs->GetParameterValue(&vz,&gauss[i][0],TemperatureEnum);
     4296                values[i]=vz;
     4297        }
     4298
     4299        /*Add value to global vector*/
     4300        VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
     4301}
     4302/*}}}*/
     4303/*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
     4304void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, double* gauss, Input* vx_input, Input* vy_input){
     4305        /*Compute the 3d Blatter/PattynStrain Rate (5 components):
     4306         *
     4307         * epsilon=[exx eyy exy exz eyz]
     4308         *
     4309         * with exz=1/2 du/dz
     4310         *      eyz=1/2 dv/dz
     4311         *
     4312         * the contribution of vz is neglected
     4313         */
     4314
     4315        int i;
     4316
     4317        double epsilonvx[5];
     4318        double epsilonvy[5];
     4319
     4320        /*Check that both inputs have been found*/
     4321        if (!vx_input || !vy_input){
     4322                ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
     4323        }
     4324
     4325        /*Get strain rate assuming that epsilon has been allocated*/
     4326        vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
     4327        vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
     4328
     4329        /*Sum all contributions*/
     4330        for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
     4331
     4332}
     4333/*}}}*/
     4334/*FUNCTION Penta::GetStrainRate3d{{{1*/
     4335void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, double* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
     4336        /*Compute the 3d Strain Rate (6 components):
     4337         *
     4338         * epsilon=[exx eyy ezz exy exz eyz]
     4339         */
     4340
     4341        int i;
     4342
     4343        double epsilonvx[6];
     4344        double epsilonvy[6];
     4345        double epsilonvz[6];
     4346
     4347        /*Check that both inputs have been found*/
     4348        if (!vx_input || !vy_input || !vz_input){
     4349                ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
     4350        }
     4351
     4352        /*Get strain rate assuming that epsilon has been allocated*/
     4353        vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
     4354        vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
     4355        vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
     4356
     4357        /*Sum all contributions*/
     4358        for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
     4359
     4360}
     4361/*}}}*/
     4362/*FUNCTION Penta::GetUpperElement{{{1*/
     4363Penta* Penta::GetUpperElement(void){
     4364
     4365        Penta* upper_penta=NULL;
     4366        upper_penta=(Penta*)neighbors[1]; //first one under, second one above
     4367        return upper_penta;
     4368
     4369}
     4370/*}}}*/
     4371/*FUNCTION Penta::GradjB {{{1*/
     4372void  Penta::GradjB(Vec gradient){
     4373
     4374        int i;
     4375        Tria* tria=NULL;
     4376        TriaVertexInput* triavertexinput=NULL;
     4377
     4378        /*inputs: */
     4379        bool onwater;
     4380        bool collapse;
     4381        bool onbed;
     4382
     4383        /*retrieve inputs :*/
     4384        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     4385        inputs->GetParameterValue(&collapse,CollapseEnum);
     4386        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     4387
     4388        /*If on water, skip: */
     4389        if(onwater)return;
     4390
     4391        if (collapse){
     4392                /*Bail out element if collapsed (2d) and not on bed*/
     4393                if (!onbed) return;
     4394
     4395                /*This element should be collapsed into a tria element at its base. Create this tria element,
     4396                 * and compute gardj*/
     4397                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     4398                tria->GradjB(gradient);
     4399                delete tria;
     4400        }
     4401        else{
     4402                /*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
     4403                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
     4404                tria->GradjB(gradient);
     4405                delete tria;
     4406        }
     4407
     4408
     4409}
     4410/*}}}*/
     4411/*FUNCTION Penta::GradjDrag {{{1*/
     4412void  Penta::GradjDrag(Vec gradient){
     4413
     4414        int i;
     4415        Tria* tria=NULL;
     4416        TriaVertexInput* triavertexinput=NULL;
     4417        double temp_gradient[6]={0,0,0,0,0,0};
     4418
     4419        /*inputs: */
     4420        bool onwater;
     4421        bool onbed;
     4422        bool shelf;
     4423        int analysis_type;
     4424
     4425        /*retrieve parameters: */
     4426        parameters->FindParam(&analysis_type,AnalysisTypeEnum);
     4427
     4428        /*retrieve inputs :*/
     4429        inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
     4430        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     4431        inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
     4432
     4433        /*If on water, skip: */
     4434        if(onwater)return;
     4435
     4436        /*If on shelf, skip: */
     4437        if(shelf)return;
     4438
     4439        /*Bail out if this element does not touch the bedrock: */
     4440        if (!onbed) return;
     4441
     4442        if (analysis_type==AdjointHorizAnalysisEnum){
     4443
     4444                /*MacAyeal or Pattyn*/
     4445                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     4446                tria->GradjDrag(gradient);
     4447                delete tria;
     4448        }
     4449        else if (analysis_type==AdjointStokesAnalysisEnum){
     4450
     4451                /*Stokes*/
     4452                tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
     4453                tria->GradjDragStokes(gradient);
     4454                delete tria;
     4455        }
     4456        else ISSMERROR("analysis %s not supported yet",EnumAsString(analysis_type));
     4457
     4458
     4459}
     4460/*}}}*/
     4461/*FUNCTION Penta::InputExtrude {{{1*/
     4462void  Penta::InputExtrude(int enum_type,bool only_if_collapsed){
     4463
     4464        bool   onbed,collapse=false;
     4465        Penta *penta          = NULL;
     4466        Input *original_input = NULL;
     4467
     4468        /*recover parameters: */
     4469        if (only_if_collapsed) inputs->GetParameterValue(&collapse,CollapseEnum);
     4470        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     4471
     4472        /*First: if only_if_collapsed, check wether this penta is collapsed*/
     4473        if (only_if_collapsed && !collapse) return;
     4474
     4475        /*Are we on the base, not on the surface?:*/
     4476        if(onbed){
     4477
     4478                /*OK, we are on bed. we will follow the steps:
     4479                 * 1: find input and extrude it.
     4480                 * 2: follow the upper element until we reach the surface
     4481                 * 3: for each element, we will add a copy of the extruded input*/
     4482
     4483                /*Step1: Extrude the original input: */
     4484                original_input=(Input*)this->inputs->GetInput(enum_type);
     4485                if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumAsString(enum_type));
     4486                original_input->Extrude();
     4487
     4488                /*Stop if there is only one layer of element*/
     4489                if (this->IsOnSurface()) return;
     4490
     4491                /*Step 2: this input has been extruded for this element, now follow the upper element*/
     4492                penta=this;
     4493                for(;;){
     4494
     4495                        /* get upper Penta*/
     4496                        penta=penta->GetUpperElement();
     4497                        ISSMASSERT(penta->Id()!=this->id);
     4498
     4499                        /*Add input of the basal element to penta->inputs*/
     4500                        Input* copy=NULL;
     4501                        copy=(Input*)original_input->copy();
     4502                        penta->inputs->AddInput((Input*)copy);
     4503
     4504                        /*Stop if we have reached the surface*/
     4505                        if (penta->IsOnSurface()) break;
     4506
     4507                }
     4508        }
     4509
     4510        return;
     4511}
     4512/*}}}*/
    21064513/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
    21074514void  Penta::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
     
    27075114                penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
    27085115        }
    2709 }
    2710 /*}}}*/
    2711 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
    2712 void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
    2713 
    2714         int i;
    2715 
    2716         const int    numvertices=6;
    2717         const int    numdofpervertex=2;
    2718         const int    numdof=numdofpervertex*numvertices;
    2719         double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    2720 
    2721         int          doflist[numdof];
    2722         double       values[numdof];
    2723         double       vx;
    2724         double       vy;
    2725 
    2726         int          dummy;
    2727 
    2728         /*Get dof list: */
    2729         GetDofList(&doflist[0],&dummy);
    2730 
    2731         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    2732         /*P1 element only for now*/
    2733         for(i=0;i<numvertices;i++){
    2734 
    2735                 /*Recover vx and vy*/
    2736                 inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
    2737                 inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
    2738                 values[i*numdofpervertex+0]=vx;
    2739                 values[i*numdofpervertex+1]=vy;
    2740         }
    2741 
    2742         /*Add value to global vector*/
    2743         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    2744 
    2745 }
    2746 /*}}}*/
    2747 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
    2748 void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
    2749 
    2750         int i;
    2751 
    2752         const int    numvertices=6;
    2753         const int    numdofpervertex=2;
    2754         const int    numdof=numdofpervertex*numvertices;
    2755         double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    2756 
    2757         int          doflist[numdof];
    2758         double       values[numdof];
    2759         double       vx;
    2760         double       vy;
    2761 
    2762         int          dummy;
    2763 
    2764         /*Get dof list: */
    2765         GetDofList(&doflist[0],&dummy);
    2766 
    2767         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    2768         /*P1 element only for now*/
    2769         for(i=0;i<numvertices;i++){
    2770 
    2771                 /*Recover vx and vy*/
    2772                 inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
    2773                 inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
    2774                 values[i*numdofpervertex+0]=vx;
    2775                 values[i*numdofpervertex+1]=vy;
    2776         }
    2777 
    2778         /*Add value to global vector*/
    2779         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    2780 
    2781 }
    2782 /*}}}*/
    2783 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
    2784 void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
    2785 
    2786         int i;
    2787 
    2788         const int    numvertices=6;
    2789         const int    numdofpervertex=1;
    2790         const int    numdof=numdofpervertex*numvertices;
    2791         double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    2792 
    2793         int          doflist[numdof];
    2794         double       values[numdof];
    2795         double       vz;
    2796 
    2797         int          dummy;
    2798 
    2799         /*Get dof list: */
    2800         GetDofList(&doflist[0],&dummy);
    2801 
    2802         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    2803         /*P1 element only for now*/
    2804         for(i=0;i<numvertices;i++){
    2805 
    2806                 /*Recover vz */
    2807                 inputs->GetParameterValue(&vz,&gauss[i][0],VxEnum);
    2808                 values[i]=vz;
    2809         }
    2810 
    2811         /*Add value to global vector*/
    2812         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    2813 }
    2814 /*}}}*/
    2815 /*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
    2816 void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
    2817 
    2818         int i;
    2819 
    2820         const int    numvertices=6;
    2821         const int    numdofpervertex=4;
    2822         const int    numdof=numdofpervertex*numvertices;
    2823         double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    2824 
    2825         int          doflist[numdof];
    2826         double       values[numdof];
    2827         double       vx,vy,vz,p;
    2828 
    2829         int          dummy;
    2830         double       stokesreconditioning;
    2831 
    2832         /*Get dof list: */
    2833         GetDofList(&doflist[0],&dummy);
    2834 
    2835         /*Recondition pressure: */
    2836         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    2837 
    2838         /*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
    2839         /*P1 element only for now*/
    2840         for(i=0;i<numvertices;i++){
    2841 
    2842                 /*Recover vx and vy*/
    2843                 inputs->GetParameterValue(&vx,&gauss[i][0],VxEnum);
    2844                 inputs->GetParameterValue(&vy,&gauss[i][0],VyEnum);
    2845                 inputs->GetParameterValue(&vz,&gauss[i][0],VzEnum);
    2846                 inputs->GetParameterValue(&p ,&gauss[i][0],PressureEnum);
    2847                 values[i*numdofpervertex+0]=vx;
    2848                 values[i*numdofpervertex+1]=vy;
    2849                 values[i*numdofpervertex+2]=vz;
    2850                 values[i*numdofpervertex+3]=p/stokesreconditioning;
    2851         }
    2852 
    2853         /*Add value to global vector*/
    2854         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    2855 
    2856 }
    2857 /*}}}*/
    2858 /*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
    2859 void  Penta::GetSolutionFromInputsThermal(Vec solution){
    2860 
    2861         int i;
    2862 
    2863         const int    numvertices=6;
    2864         const int    numdofpervertex=1;
    2865         const int    numdof=numdofpervertex*numvertices;
    2866         double       gauss[numvertices][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    2867 
    2868         int          doflist[numdof];
    2869         double       values[numdof];
    2870         double       vz;
    2871 
    2872         int          dummy;
    2873 
    2874         /*Get dof list: */
    2875         GetDofList(&doflist[0],&dummy);
    2876 
    2877         /*Ok, we have vx and vy in values, fill in vx and vy arrays: */
    2878         /*P1 element only for now*/
    2879         for(i=0;i<numvertices;i++){
    2880 
    2881                 /*Recover vz */
    2882                 inputs->GetParameterValue(&vz,&gauss[i][0],TemperatureEnum);
    2883                 values[i]=vz;
    2884         }
    2885 
    2886         /*Add value to global vector*/
    2887         VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
    28885116}
    28895117/*}}}*/
     
    29265154}
    29275155/*}}}*/
    2928 /*FUNCTION Penta::GetUpperElement{{{1*/
    2929 Penta* Penta::GetUpperElement(void){
    2930 
    2931         Penta* upper_penta=NULL;
    2932         upper_penta=(Penta*)neighbors[1]; //first one under, second one above
    2933         return upper_penta;
    2934 
    2935 }
    2936 /*}}}*/
    2937 /*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
    2938 
    2939 void  Penta::CreateKMatrixBalancedthickness(Mat Kgg){
    2940 
    2941         /*Collapsed formulation: */
    2942         Tria*  tria=NULL;
    2943 
    2944         /*flags: */
    2945         bool onwater;
    2946         bool onbed;
    2947 
    2948         /*recover some inputs: */
    2949         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    2950         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    2951 
    2952         /*If on water, skip: */
    2953         if(onwater)return;
    2954 
    2955         /*Is this element on the bed? :*/
    2956         if(!onbed)return;
    2957 
    2958         /*Spawn Tria element from the base of the Penta: */
    2959         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2960         tria->CreateKMatrix(Kgg);
    2961         delete tria;
    2962         return;
    2963 
    2964 }
    2965 /*}}}*/
    2966 /*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
    2967 
    2968 void  Penta::CreateKMatrixBalancedvelocities(Mat Kgg){
    2969 
    2970         /*Collapsed formulation: */
    2971         Tria*  tria=NULL;
    2972 
    2973         /*flags: */
    2974         bool onbed;
    2975         bool onwater;
    2976 
    2977         /*recover some inputs: */
    2978         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    2979         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    2980 
    2981         /*If on water, skip: */
    2982         if(onwater)return;
    2983 
    2984         /*Is this element on the bed? :*/
    2985         if(!onbed)return;
    2986 
    2987         /*Spawn Tria element from the base of the Penta: */
    2988         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    2989         tria->CreateKMatrix(Kgg);
    2990         delete tria;
    2991         return;
    2992 
    2993 }
    2994 /*}}}*/
    2995 /*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
    2996 void Penta::CreateKMatrixDiagnosticHoriz( Mat Kgg){
    2997 
    2998         /* local declarations */
    2999         int             i,j;
    3000 
    3001         /* node data: */
    3002         const int    numgrids=6;
    3003         const int    numdof=2*numgrids;
    3004         double       xyz_list[numgrids][3];
    3005         int          doflist[numdof];
    3006         int          numberofdofspernode;
    3007 
    3008         /* 3d gaussian points: */
    3009         int     num_gauss,ig;
    3010         double* first_gauss_area_coord  =  NULL;
    3011         double* second_gauss_area_coord =  NULL;
    3012         double* third_gauss_area_coord  =  NULL;
    3013         double* fourth_gauss_vert_coord  =  NULL;
    3014         double* area_gauss_weights           =  NULL;
    3015         double* vert_gauss_weights           =  NULL;
    3016         int     ig1,ig2;
    3017         double  gauss_weight1,gauss_weight2;
    3018         double  gauss_coord[4];
    3019         int     order_area_gauss;
    3020         int     num_vert_gauss;
    3021         int     num_area_gauss;
    3022         double  gauss_weight;
    3023 
    3024         /* 2d gaussian point: */
    3025         int     num_gauss2d;
    3026         double* first_gauss_area_coord2d  =  NULL;
    3027         double* second_gauss_area_coord2d =  NULL;
    3028         double* third_gauss_area_coord2d  =  NULL;
    3029         double* gauss_weights2d=NULL;
    3030         double  gauss_l1l2l3[3];
    3031 
    3032         /* material data: */
    3033         double viscosity; //viscosity
    3034         double oldviscosity; //viscosity
    3035         double newviscosity; //viscosity
    3036 
    3037         /* strain rate: */
    3038         double epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
    3039         double oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
    3040 
    3041         /* matrices: */
    3042         double B[5][numdof];
    3043         double Bprime[5][numdof];
    3044         double L[2][numdof];
    3045         double D[5][5]={0.0};            // material matrix, simple scalar matrix.
    3046         double D_scalar;
    3047         double DL[2][2]={0.0}; //for basal drag
    3048         double DL_scalar;
    3049 
    3050         /* local element matrices: */
    3051         double Ke_gg[numdof][numdof]={0.0}; //local element stiffness matrix
    3052 
    3053         double Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
    3054         double Ke_gg_drag_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
    3055         double Jdet;
    3056 
    3057         /*slope: */
    3058         double  slope[2]={0.0};
    3059         double  slope_magnitude;
    3060 
    3061         /*friction: */
    3062         double  alpha2_list[3];
    3063         double  alpha2;
    3064 
    3065         double MAXSLOPE=.06; // 6 %
    3066         double MOUNTAINKEXPONENT=10;
    3067 
    3068         /*parameters: */
    3069         double viscosity_overshoot;
    3070 
    3071         /*Collapsed formulation: */
    3072         Tria*  tria=NULL;
    3073 
    3074         /*inputs: */
    3075         bool onwater;
    3076         bool collapse;
    3077         bool onbed;
    3078         bool shelf;
    3079         Input* vx_input=NULL;
    3080         Input* vy_input=NULL;
    3081         Input* vxold_input=NULL;
    3082         Input* vyold_input=NULL;
    3083 
    3084         /*retrieve inputs :*/
    3085         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3086         inputs->GetParameterValue(&collapse,CollapseEnum);
    3087         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3088         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    3089 
    3090         /*retrieve some parameters: */
    3091         this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
    3092 
    3093         /*If on water, skip stiffness: */
    3094         if(onwater)return;
    3095 
    3096         /*Figure out if this pentaelem is collapsed. If so, then bailout, except if it is at the
    3097           bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
    3098           the stiffness matrix. */
    3099 
    3100         if ((collapse==1) && (onbed==0)){
    3101                 /*This element should be collapsed, but this element is not on the bedrock, therefore all its
    3102                  * dofs have already been frozen! Do nothing: */
    3103                 return;
    3104         }
    3105         else if ((collapse==1) && (onbed==1)){
    3106 
    3107                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    3108                  *and use its CreateKMatrix functionality to fill the global stiffness matrix: */
    3109                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3110                 tria->CreateKMatrix(Kgg);
    3111                 delete tria;
    3112                 return;
    3113         }
    3114         else{
    3115 
    3116                 /*Implement standard penta element: */
    3117 
    3118                 /* Get node coordinates and dof list: */
    3119                 GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    3120                 GetDofList(&doflist[0],&numberofdofspernode);
    3121 
    3122                 /*Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    3123                   get tria gaussian points as well as segment gaussian points. For tria gaussian
    3124                   points, order of integration is 2, because we need to integrate the product tB*D*B'
    3125                   which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    3126                   points, same deal, which yields 3 gaussian points.*/
    3127 
    3128                 order_area_gauss=5;
    3129                 num_vert_gauss=5;
    3130 
    3131                 GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
    3132 
    3133                 /*Retrieve all inputs we will be needing: */
    3134                 vx_input=inputs->GetInput(VxEnum);
    3135                 vy_input=inputs->GetInput(VyEnum);
    3136                 vxold_input=inputs->GetInput(VxOldEnum);
    3137                 vyold_input=inputs->GetInput(VyOldEnum);
    3138 
    3139                 /* Start  looping on the number of gaussian points: */
    3140                 for (ig1=0; ig1<num_area_gauss; ig1++){
    3141                         for (ig2=0; ig2<num_vert_gauss; ig2++){
    3142 
    3143                                 /*Pick up the gaussian point: */
    3144                                 gauss_weight1=*(area_gauss_weights+ig1);
    3145                                 gauss_weight2=*(vert_gauss_weights+ig2);
    3146                                 gauss_weight=gauss_weight1*gauss_weight2;
    3147 
    3148 
    3149                                 gauss_coord[0]=*(first_gauss_area_coord+ig1);
    3150                                 gauss_coord[1]=*(second_gauss_area_coord+ig1);
    3151                                 gauss_coord[2]=*(third_gauss_area_coord+ig1);
    3152                                 gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
    3153 
    3154 
    3155                                 /*Get strain rate from velocity: */
    3156                                 this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input);
    3157                                 this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss_coord,vxold_input,vyold_input);
    3158 
    3159                                 /*Get viscosity: */
    3160                                 matice->GetViscosity3d(&viscosity, &epsilon[0]);
    3161                                 matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
    3162 
    3163                                 /*Get B and Bprime matrices: */
    3164                                 GetB(&B[0][0], &xyz_list[0][0], gauss_coord);
    3165                                 GetBPrime(&Bprime[0][0], &xyz_list[0][0], gauss_coord);
    3166 
    3167                                 /* Get Jacobian determinant: */
    3168                                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    3169 
    3170                                 /*Build the D matrix: we plug the gaussian weight, the viscosity, and the jacobian determinant
    3171                                   onto this scalar matrix, so that we win some computational time: */
    3172 
    3173                                 newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
    3174                                 D_scalar=newviscosity*gauss_weight*Jdet;
    3175                                 for (i=0;i<5;i++){
    3176                                         D[i][i]=D_scalar;
    3177                                 }
    3178 
    3179                                 /*  Do the triple product tB*D*Bprime: */
    3180                                 TripleMultiply( &B[0][0],5,numdof,1,
    3181                                                         &D[0][0],5,5,0,
    3182                                                         &Bprime[0][0],5,numdof,0,
    3183                                                         &Ke_gg_gaussian[0][0],0);
    3184 
    3185                                 /* Add the Ke_gg_gaussian, and optionally Ke_gg_gaussian onto Ke_gg: */
    3186                                 for( i=0; i<numdof; i++){
    3187                                         for(j=0;j<numdof;j++){
    3188                                                 Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
    3189                                         }
    3190                                 }
    3191                         } //for (ig2=0; ig2<num_vert_gauss; ig2++)
    3192                 } //for (ig1=0; ig1<num_area_gauss; ig1++)
    3193 
    3194 
    3195                 /*Add Ke_gg to global matrix Kgg: */
    3196                 MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
    3197 
    3198                 //Deal with 2d friction at the bedrock interface
    3199                 if((onbed && !shelf)){
    3200 
    3201                         /*Build a tria element using the 3 grids of the base of the penta. Then use
    3202                          * the tria functionality to build a friction stiffness matrix on these 3
    3203                          * grids: */
    3204 
    3205                         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3206                         tria->CreateKMatrixDiagnosticHorizFriction(Kgg);
    3207                         delete tria;
    3208                 }
    3209 
    3210         }
    3211 
    3212         xfree((void**)&first_gauss_area_coord);
    3213         xfree((void**)&second_gauss_area_coord);
    3214         xfree((void**)&third_gauss_area_coord);
    3215         xfree((void**)&fourth_gauss_vert_coord);
    3216         xfree((void**)&area_gauss_weights);
    3217         xfree((void**)&vert_gauss_weights);
    3218         xfree((void**)&first_gauss_area_coord2d);
    3219         xfree((void**)&second_gauss_area_coord2d);
    3220         xfree((void**)&third_gauss_area_coord2d);
    3221         xfree((void**)&gauss_weights2d);
    3222 
    3223 }
    3224 /*}}}*/
    3225 /*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
    3226 void  Penta::CreateKMatrixDiagnosticHutter(Mat Kgg){
    3227 
    3228         /*Collapsed formulation: */
    3229         Beam*  beam=NULL;
    3230         int    i;
    3231 
    3232         /*flags: */
    3233         bool onwater;
    3234 
    3235         /*recover some inputs: */
    3236         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3237 
    3238         /*If on water, skip: */
    3239         if(onwater)return;
    3240 
    3241         /*Spawn 3 beam elements: */
    3242         for(i=0;i<3;i++){
    3243                 beam=(Beam*)SpawnBeam(i,i+3); //[0 3], [1 4] and [2 5] are the four vertical edges of the Penta
    3244                 beam->CreateKMatrix(Kgg);
    3245         }
    3246 
    3247         /*clean up*/
    3248         delete beam;
    3249 
    3250 }
    3251 /*}}}*/
    3252 /*FUNCTION Penta::CreateKMatrixDiagnosticStokes {{{1*/
    3253 void Penta::CreateKMatrixDiagnosticStokes( Mat Kgg){
    3254 
    3255         int i,j;
    3256 
    3257         const int numgrids=6;
    3258         const int DOFPERGRID=4;
    3259         const int numdof=numgrids*DOFPERGRID;
    3260         int doflist[numdof];
    3261         int numberofdofspernode;
    3262 
    3263         const int numgrids2d=3;
    3264         const int numdof2d=numgrids2d*DOFPERGRID;
    3265 
    3266         int   dofs[3]={0,1,2};
    3267 
    3268         double K_terms[numdof][numdof]={0.0};
    3269 
    3270         /*Material properties: */
    3271         double         gravity,rho_ice,rho_water;
    3272 
    3273         /*Collapsed formulation: */
    3274         Tria*  tria=NULL;
    3275 
    3276         /*Grid data: */
    3277         double        xyz_list[numgrids][3];
    3278 
    3279         /*parameters: */
    3280         double             xyz_list_tria[numgrids2d][3];
    3281         double             surface_normal[3];
    3282         double             bed_normal[3];
    3283         double         thickness;
    3284 
    3285         /*matrices: */
    3286         double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble
    3287         double     Ke_reduced[numdof][numdof]; //for the six nodes only
    3288         double     Ke_gaussian[27][27];
    3289         double     Ke_drag_gaussian[numdof2d][numdof2d];
    3290         double     B[8][27];
    3291         double     B_prime[8][27];
    3292         double     LStokes[14][numdof2d];
    3293         double     LprimeStokes[14][numdof2d];
    3294         double     Jdet;
    3295         double     Jdet2d;
    3296         double     D[8][8]={0.0};
    3297         double     D_scalar;
    3298         double     tBD[27][8];
    3299         double     DLStokes[14][14]={0.0};
    3300         double     tLDStokes[numdof2d][14];
    3301 
    3302         /* gaussian points: */
    3303         int     num_area_gauss;
    3304         int     igarea,igvert;
    3305         double* first_gauss_area_coord  =  NULL;
    3306         double* second_gauss_area_coord =  NULL;
    3307         double* third_gauss_area_coord  =  NULL;
    3308         double* vert_gauss_coord = NULL;
    3309         double* area_gauss_weights  =  NULL;
    3310         double* vert_gauss_weights  =  NULL;
    3311         double  gaussgrids[numgrids][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    3312 
    3313         /* specific gaussian point: */
    3314         double  gauss_weight,area_gauss_weight,vert_gauss_weight;
    3315         double  gauss_coord[4];
    3316         double  gauss_coord_tria[3];
    3317         int area_order=5;
    3318         int     num_vert_gauss=5;
    3319 
    3320         double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    3321         double  viscosity;
    3322         double  alpha2_gauss;
    3323         Friction* friction=NULL;
    3324 
    3325         /*parameters: */
    3326         double stokesreconditioning;
    3327         int analysis_type;
    3328 
    3329         /*inputs: */
    3330         bool onwater;
    3331         bool onbed;
    3332         bool shelf;
    3333         bool isstokes;
    3334 
    3335         /*inputs: */
    3336         Input* vx_input=NULL;
    3337         Input* vy_input=NULL;
    3338         Input* vz_input=NULL;
    3339 
    3340         /*retrive parameters: */
    3341         parameters->FindParam(&analysis_type,AnalysisTypeEnum);
    3342 
    3343         /*retrieve inputs :*/
    3344         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3345         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3346         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    3347         inputs->GetParameterValue(&isstokes,IsStokesEnum);
    3348 
    3349         /*If on water or not Stokes, skip stiffness: */
    3350         if(onwater || !isstokes) return;
    3351 
    3352         /*recovre material parameters: */
    3353         rho_water=matpar->GetRhoWater();
    3354         rho_ice=matpar->GetRhoIce();
    3355         gravity=matpar->GetG();
    3356 
    3357         /*retrieve some parameters: */
    3358         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    3359 
    3360         /* Get node coordinates and dof list: */
    3361         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    3362         GetDofList(&doflist[0],&numberofdofspernode);
    3363 
    3364         /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    3365                 get tria gaussian points as well as segment gaussian points. For tria gaussian
    3366                 points, order of integration is 2, because we need to integrate the product tB*D*B'
    3367                 which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    3368                 points, same deal, which yields 3 gaussian points.*/
    3369 
    3370         area_order=5;
    3371         num_vert_gauss=5;
    3372 
    3373         /* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
    3374         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
    3375 
    3376         /*Retrieve all inputs we will be needing: */
    3377         vx_input=inputs->GetInput(VxEnum);
    3378         vy_input=inputs->GetInput(VyEnum);
    3379         vz_input=inputs->GetInput(VzEnum);
    3380 
    3381         /* Start  looping on the number of gaussian points: */
    3382         for (igarea=0; igarea<num_area_gauss; igarea++){
    3383                 for (igvert=0; igvert<num_vert_gauss; igvert++){
    3384                         /*Pick up the gaussian point: */
    3385                         area_gauss_weight=*(area_gauss_weights+igarea);
    3386                         vert_gauss_weight=*(vert_gauss_weights+igvert);
    3387                         gauss_weight=area_gauss_weight*vert_gauss_weight;
    3388                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    3389                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    3390                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    3391                         gauss_coord[3]=*(vert_gauss_coord+igvert);
    3392 
    3393                         /*Compute strain rate: */
    3394                         this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
    3395 
    3396                         /*Get viscosity: */
    3397                         matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3398 
    3399                         /*Get B and Bprime matrices: */
    3400                         GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord);
    3401                         GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord);
    3402 
    3403                         /* Get Jacobian determinant: */
    3404                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],&gauss_coord[0]);
    3405 
    3406                         /* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant
    3407                          * onto this scalar matrix, so that we win some computational time: */
    3408                         D_scalar=gauss_weight*Jdet;
    3409                         for (i=0;i<6;i++){
    3410                                 D[i][i]=D_scalar*viscosity;
    3411                         }
    3412                         for (i=6;i<8;i++){
    3413                                 D[i][i]=-D_scalar*stokesreconditioning;
    3414                         }
    3415 
    3416                         /*  Do the triple product tB*D*Bprime: */
    3417                         MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
    3418                         MatrixMultiply(&tBD[0][0],27,8,0,&B_prime[0][0],8,27,0,&Ke_gaussian[0][0],0);
    3419 
    3420                         /*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
    3421                         for(i=0;i<27;i++){
    3422                                 for(j=0;j<27;j++){
    3423                                         Ke_temp[i][j]+=Ke_gaussian[i][j];
    3424                                 }
    3425                         }
    3426                 }
    3427         }
    3428 
    3429         if((onbed==1) && (shelf==0)){
    3430 
    3431                 /*build friction object, used later on: */
    3432                 friction=new Friction("3d",inputs,matpar,analysis_type);
    3433 
    3434                 for(i=0;i<numgrids2d;i++){
    3435                         for(j=0;j<3;j++){
    3436                                 xyz_list_tria[i][j]=xyz_list[i][j];
    3437                         }
    3438                 }
    3439 
    3440                 xfree((void**)&first_gauss_area_coord); xfree((void**)&second_gauss_area_coord); xfree((void**)&third_gauss_area_coord); xfree((void**)&area_gauss_weights);
    3441                 GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
    3442 
    3443                 /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    3444                 for (igarea=0; igarea<num_area_gauss; igarea++){
    3445                         gauss_weight=*(area_gauss_weights+igarea);
    3446                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    3447                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    3448                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    3449                         gauss_coord[3]=-1;
    3450 
    3451                         gauss_coord_tria[0]=*(first_gauss_area_coord+igarea);
    3452                         gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
    3453                         gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
    3454 
    3455                         /*Get the Jacobian determinant */
    3456                         tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
    3457 
    3458                         /*Get L matrix if viscous basal drag present: */
    3459                         GetLStokes(&LStokes[0][0],  gauss_coord_tria);
    3460                         GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss_coord_tria, gauss_coord);
    3461 
    3462                         /*Compute strain rate: */
    3463                         this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
    3464 
    3465                         /*Get viscosity at last iteration: */
    3466                         matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    3467 
    3468                         /*Get normal vecyor to the bed */
    3469                         SurfaceNormal(&surface_normal[0],xyz_list_tria);
    3470 
    3471                         bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
    3472                         bed_normal[1]=-surface_normal[1];
    3473                         bed_normal[2]=-surface_normal[2];
    3474 
    3475                         /*Calculate DL on gauss point */
    3476                         friction->GetAlpha2(&alpha2_gauss, gauss_coord,VxEnum,VyEnum,VzEnum);
    3477 
    3478                         DLStokes[0][0]=alpha2_gauss*gauss_weight*Jdet2d;
    3479                         DLStokes[1][1]=alpha2_gauss*gauss_weight*Jdet2d;
    3480                         DLStokes[2][2]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
    3481                         DLStokes[3][3]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
    3482                         DLStokes[4][4]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
    3483                         DLStokes[5][5]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
    3484                         DLStokes[6][6]=-viscosity*gauss_weight*Jdet2d*bed_normal[0];
    3485                         DLStokes[7][7]=-viscosity*gauss_weight*Jdet2d*bed_normal[1];
    3486                         DLStokes[8][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[2];
    3487                         DLStokes[9][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[0]/2.0;
    3488                         DLStokes[10][10]=-viscosity*gauss_weight*Jdet2d*bed_normal[1]/2.0;
    3489                         DLStokes[11][11]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[0];
    3490                         DLStokes[12][12]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[1];
    3491                         DLStokes[13][13]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[2];
    3492 
    3493                         /*  Do the triple product tL*D*L: */
    3494                         MatrixMultiply(&LStokes[0][0],14,numdof2d,1,&DLStokes[0][0],14,14,0,&tLDStokes[0][0],0);
    3495                         MatrixMultiply(&tLDStokes[0][0],numdof2d,14,0,&LprimeStokes[0][0],14,numdof2d,0,&Ke_drag_gaussian[0][0],0);
    3496 
    3497                         for(i=0;i<numdof2d;i++){
    3498                                 for(j=0;j<numdof2d;j++){
    3499                                         Ke_temp[i][j]+=Ke_drag_gaussian[i][j];
    3500                                 }
    3501                         }
    3502                 }
    3503        
    3504                 /*Free ressources:*/
    3505                 delete friction;
    3506 
    3507         } //if ( (onbed==1) && (shelf==0))
    3508 
    3509         /*Reduce the matrix */
    3510         ReduceMatrixStokes(&Ke_reduced[0][0], &Ke_temp[0][0]);
    3511 
    3512         for(i=0;i<numdof;i++){
    3513                 for(j=0;j<numdof;j++){
    3514                         K_terms[i][j]+=Ke_reduced[i][j];
    3515                 }
    3516         }
    3517 
    3518         /*Add Ke_gg to global matrix Kgg: */
    3519         MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)K_terms,ADD_VALUES);
    3520 
    3521 
    3522         /*Free ressources:*/
    3523         xfree((void**)&first_gauss_area_coord);
    3524         xfree((void**)&second_gauss_area_coord);
    3525         xfree((void**)&third_gauss_area_coord);
    3526         xfree((void**)&area_gauss_weights);
    3527         xfree((void**)&vert_gauss_coord);
    3528         xfree((void**)&vert_gauss_weights);
    3529 
    3530         return;
    3531 }
    3532 /*}}}*/
    3533 /*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
    3534 void Penta::CreateKMatrixDiagnosticVert( Mat Kgg){
    3535 
    3536         /* local declarations */
    3537         int             i,j;
    3538 
    3539         /* node data: */
    3540         const int    numgrids=6;
    3541         const int    NDOF1=1;
    3542         const int    numdof=NDOF1*numgrids;
    3543         double       xyz_list[numgrids][3];
    3544         int          doflist[numdof];
    3545         int          numberofdofspernode;
    3546 
    3547         /* 3d gaussian points: */
    3548         int     num_gauss,ig;
    3549         double* first_gauss_area_coord  =  NULL;
    3550         double* second_gauss_area_coord =  NULL;
    3551         double* third_gauss_area_coord  =  NULL;
    3552         double* fourth_gauss_vert_coord  =  NULL;
    3553         double* area_gauss_weights           =  NULL;
    3554         double* vert_gauss_weights           =  NULL;
    3555         int     ig1,ig2;
    3556         double  gauss_weight1,gauss_weight2;
    3557         double  gauss_coord[4];
    3558         int     order_area_gauss;
    3559         int     num_vert_gauss;
    3560         int     num_area_gauss;
    3561         double  gauss_weight;
    3562 
    3563         /* matrices: */
    3564         double  Ke_gg[numdof][numdof]={0.0};
    3565         double  Ke_gg_gaussian[numdof][numdof];
    3566         double  Jdet;
    3567         double  B[NDOF1][numgrids];
    3568         double  Bprime[NDOF1][numgrids];
    3569         double  DL_scalar;
    3570 
    3571         /*Collapsed formulation: */
    3572         Tria*  tria=NULL;
    3573 
    3574         /*inputs: */
    3575         bool onwater;
    3576         bool onsurface;
    3577 
    3578         /*retrieve inputs :*/
    3579         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3580         inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
    3581 
    3582         /*If on water, skip stiffness: */
    3583         if(onwater)return;
    3584 
    3585         /*If this element  is on the surface, we have a dynamic boundary condition that applies, as a stiffness
    3586          * matrix: */
    3587         if(onsurface){
    3588                 tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
    3589                 tria->CreateKMatrixDiagnosticSurfaceVert(Kgg);
    3590                 delete tria;
    3591         }
    3592 
    3593         /*Now, onto the formulation for the vertical velocity: */
    3594 
    3595         /* Get node coordinates and dof list: */
    3596         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    3597         GetDofList(&doflist[0],&numberofdofspernode);
    3598 
    3599         /*Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    3600           get tria gaussian points as well as segment gaussian points. For tria gaussian
    3601           points, order of integration is 2, because we need to integrate the product tB*D*B'
    3602           which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    3603           points, same deal, which yields 3 gaussian points.*/
    3604 
    3605         order_area_gauss=2;
    3606         num_vert_gauss=2;
    3607 
    3608         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
    3609 
    3610         /* Start  looping on the number of gaussian points: */
    3611         for (ig1=0; ig1<num_area_gauss; ig1++){
    3612                 for (ig2=0; ig2<num_vert_gauss; ig2++){
    3613 
    3614                         /*Pick up the gaussian point: */
    3615                         gauss_weight1=*(area_gauss_weights+ig1);
    3616                         gauss_weight2=*(vert_gauss_weights+ig2);
    3617                         gauss_weight=gauss_weight1*gauss_weight2;
    3618 
    3619                         gauss_coord[0]=*(first_gauss_area_coord+ig1);
    3620                         gauss_coord[1]=*(second_gauss_area_coord+ig1);
    3621                         gauss_coord[2]=*(third_gauss_area_coord+ig1);
    3622                         gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
    3623 
    3624                         /*Get B and Bprime matrices: */
    3625                         GetB_vert(&B[0][0], &xyz_list[0][0], gauss_coord);
    3626                         GetBPrime_vert(&Bprime[0][0], &xyz_list[0][0], gauss_coord);
    3627 
    3628                         /* Get Jacobian determinant: */
    3629                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    3630                         DL_scalar=gauss_weight*Jdet;
    3631 
    3632                         /*  Do the triple product tB*D*Bprime: */
    3633                         TripleMultiply( &B[0][0],1,numgrids,1,
    3634                                                 &DL_scalar,1,1,0,
    3635                                                 &Bprime[0][0],1,numgrids,0,
    3636                                                 &Ke_gg_gaussian[0][0],0);
    3637 
    3638                         /* Add the Ke_gg_gaussian, and optionally Ke_gg_drag_gaussian onto Ke_gg: */
    3639                         for( i=0; i<numdof; i++){
    3640                                 for(j=0;j<numdof;j++){
    3641                                         Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
    3642                                 }
    3643                         }       
    3644                 } //for (ig2=0; ig2<num_vert_gauss; ig2++)
    3645         } //for (ig1=0; ig1<num_area_gauss; ig1++)
    3646 
    3647         /*Add Ke_gg to global matrix Kgg: */
    3648         MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
    3649 
    3650         xfree((void**)&first_gauss_area_coord);
    3651         xfree((void**)&second_gauss_area_coord);
    3652         xfree((void**)&third_gauss_area_coord);
    3653         xfree((void**)&fourth_gauss_vert_coord);
    3654         xfree((void**)&area_gauss_weights);
    3655         xfree((void**)&vert_gauss_weights);
    3656 }
    3657 /*}}}*/
    3658 /*FUNCTION Penta::CreateKMatrixMelting {{{1*/
    3659 void  Penta::CreateKMatrixMelting(Mat Kgg){
    3660 
    3661         Tria* tria=NULL;
    3662 
    3663         /*inputs: */
    3664         bool onwater;
    3665         bool onbed;
    3666 
    3667         /*retrieve inputs :*/
    3668         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3669         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3670 
    3671         /*If on water, skip: */
    3672         if(onwater)return;
    3673 
    3674         if (!onbed){
    3675                 return;
    3676         }
    3677         else{
    3678 
    3679                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3680                 tria->CreateKMatrixMelting(Kgg);
    3681                 delete tria;
    3682                 return;
    3683         }
    3684 }
    3685 /*}}}*/
    3686 /*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
    3687 
    3688 void  Penta::CreateKMatrixPrognostic(Mat Kgg){
    3689 
    3690         /*Collapsed formulation: */
    3691         Tria*  tria=NULL;
    3692 
    3693         /*inputs: */
    3694         bool onwater;
    3695         bool onbed;
    3696 
    3697         /*retrieve inputs :*/
    3698         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3699         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3700 
    3701         /*If on water, skip: */
    3702         if(onwater)return;
    3703 
    3704         /*Is this element on the bed? :*/
    3705         if(!onbed)return;
    3706 
    3707         /*Spawn Tria element from the base of the Penta: */
    3708         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3709         tria->CreateKMatrix(Kgg);
    3710         delete tria;
    3711         return;
    3712 
    3713 }
    3714 /*}}}*/
    3715 /*FUNCTION Penta::CreateKMatrixSlope {{{1*/
    3716 
    3717 void  Penta::CreateKMatrixSlope(Mat Kgg){
    3718 
    3719         /*Collapsed formulation: */
    3720         Tria*  tria=NULL;
    3721 
    3722         /*inputs: */
    3723         bool onwater;
    3724         bool onbed;
    3725 
    3726         /*retrieve inputs :*/
    3727         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3728         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3729 
    3730 
    3731         /*If on water, skip: */
    3732         if(onwater)return;
    3733 
    3734         /*Is this element on the bed? :*/
    3735         if(!onbed)return;
    3736 
    3737         /*Spawn Tria element from the base of the Penta: */
    3738         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3739         tria->CreateKMatrix(Kgg);
    3740         delete tria;
    3741         return;
    3742 
    3743 }
    3744 /*}}}*/
    3745 /*FUNCTION Penta::CreateKMatrixThermal {{{1*/
    3746 void  Penta::CreateKMatrixThermal(Mat Kgg){
    3747 
    3748         /* local declarations */
    3749         int i,j;
    3750         int found=0;
    3751 
    3752         /* node data: */
    3753         const int    numgrids=6;
    3754         const int    NDOF1=1;
    3755         const int    numdof=NDOF1*numgrids;
    3756         double xyz_list[numgrids][3];
    3757         int    doflist[numdof];
    3758         int    numberofdofspernode;
    3759 
    3760         /* gaussian points: */
    3761         int     num_area_gauss,igarea,igvert;
    3762         double* first_gauss_area_coord  =  NULL;
    3763         double* second_gauss_area_coord =  NULL;
    3764         double* third_gauss_area_coord  =  NULL;
    3765         double* vert_gauss_coord = NULL;
    3766         double* area_gauss_weights  =  NULL;
    3767         double* vert_gauss_weights  =  NULL;
    3768         double  gauss_weight,area_gauss_weight,vert_gauss_weight;
    3769         double  gauss_coord[4];
    3770         double  gauss_l1l2l3[3];
    3771 
    3772         int area_order=5;
    3773         int num_vert_gauss=5;
    3774 
    3775         int     dofs[3]={0,1,2};
    3776         double  K[2][2]={0.0};
    3777 
    3778         double  u,v,w;
    3779 
    3780         /*matrices: */
    3781         double     K_terms[numdof][numdof]={0.0};
    3782         double     Ke_gaussian_conduct[numdof][numdof];
    3783         double     Ke_gaussian_advec[numdof][numdof];
    3784         double     Ke_gaussian_artdiff[numdof][numdof];
    3785         double     Ke_gaussian_transient[numdof][numdof];
    3786         double     B[3][numdof];
    3787         double     Bprime[3][numdof];
    3788         double     B_conduct[3][numdof];
    3789         double     B_advec[3][numdof];
    3790         double     B_artdiff[2][numdof];
    3791         double     Bprime_advec[3][numdof];
    3792         double     L[numdof];
    3793         double     D_scalar;
    3794         double     D[3][3];
    3795         double     l1l2l3[3];
    3796         double     tl1l2l3D[3];
    3797         double     tBD[3][numdof];
    3798         double     tBD_conduct[3][numdof];
    3799         double     tBD_advec[3][numdof];
    3800         double     tBD_artdiff[3][numdof];
    3801         double     tLD[numdof];
    3802 
    3803         double     Jdet;
    3804 
    3805         /*Material properties: */
    3806         double     gravity,rho_ice,rho_water;
    3807         double     heatcapacity,thermalconductivity;
    3808         double     mixed_layer_capacity,thermal_exchange_velocity;
    3809 
    3810         /*parameters: */
    3811         double dt,epsvel;
    3812         bool   artdiff;
    3813 
    3814         /*Collapsed formulation: */
    3815         Tria*  tria=NULL;
    3816 
    3817 
    3818         /*inputs: */
    3819         bool onwater;
    3820         bool onbed;
    3821         bool shelf;
    3822 
    3823         /*retrieve inputs :*/
    3824         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    3825         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    3826         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    3827 
    3828         /*If on water, skip: */
    3829         if(onwater)return;
    3830 
    3831         /* Get node coordinates and dof list: */
    3832         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    3833         GetDofList(&doflist[0],&numberofdofspernode);
    3834 
    3835         // /*recovre material parameters: */
    3836         rho_water=matpar->GetRhoWater();
    3837         rho_ice=matpar->GetRhoIce();
    3838         gravity=matpar->GetG();
    3839         heatcapacity=matpar->GetHeatCapacity();
    3840         thermalconductivity=matpar->GetThermalConductivity();
    3841 
    3842         /*retrieve some parameters: */
    3843         this->parameters->FindParam(&dt,DtEnum);
    3844         this->parameters->FindParam(&artdiff,ArtDiffEnum);
    3845         this->parameters->FindParam(&epsvel,EpsVelEnum);
    3846 
    3847         /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    3848                 get tria gaussian points as well as segment gaussian points. For tria gaussian
    3849                 points, order of integration is 2, because we need to integrate the product tB*D*B'
    3850                 which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    3851                 points, same deal, which yields 3 gaussian points.: */
    3852 
    3853         /*Get gaussian points: */
    3854         area_order=2;
    3855         num_vert_gauss=2;
    3856 
    3857         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
    3858 
    3859         /* Start  looping on the number of gaussian points: */
    3860         for (igarea=0; igarea<num_area_gauss; igarea++){
    3861                 for (igvert=0; igvert<num_vert_gauss; igvert++){
    3862                         /*Pick up the gaussian point: */
    3863                         area_gauss_weight=*(area_gauss_weights+igarea);
    3864                         vert_gauss_weight=*(vert_gauss_weights+igvert);
    3865                         gauss_weight=area_gauss_weight*vert_gauss_weight;
    3866                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    3867                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    3868                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    3869                         gauss_coord[3]=*(vert_gauss_coord+igvert);
    3870 
    3871                         /* Get Jacobian determinant: */
    3872                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    3873 
    3874                         /*Conduction: */
    3875 
    3876                         /*Get B_conduct matrix: */
    3877                         GetB_conduct(&B_conduct[0][0],&xyz_list[0][0],gauss_coord);
    3878 
    3879                         /*Build D: */
    3880                         D_scalar=gauss_weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
    3881 
    3882                         if(dt){
    3883                                 D_scalar=D_scalar*dt;
    3884                         }
    3885 
    3886                         D[0][0]=D_scalar; D[0][1]=0; D[0][2]=0;
    3887                         D[1][0]=0; D[1][1]=D_scalar; D[1][2]=0;
    3888                         D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar;
    3889 
    3890                         /*  Do the triple product B'*D*B: */
    3891                         MatrixMultiply(&B_conduct[0][0],3,numdof,1,&D[0][0],3,3,0,&tBD_conduct[0][0],0);
    3892                         MatrixMultiply(&tBD_conduct[0][0],numdof,3,0,&B_conduct[0][0],3,numdof,0,&Ke_gaussian_conduct[0][0],0);
    3893 
    3894                         /*Advection: */
    3895 
    3896                         /*Get B_advec and Bprime_advec matrices: */
    3897                         GetB_advec(&B_advec[0][0],&xyz_list[0][0],gauss_coord);
    3898                         GetBprime_advec(&Bprime_advec[0][0],&xyz_list[0][0],gauss_coord);
    3899 
    3900                         //Build the D matrix
    3901                         inputs->GetParameterValue(&u, gauss_coord,VxEnum);
    3902                         inputs->GetParameterValue(&v, gauss_coord,VyEnum);
    3903                         inputs->GetParameterValue(&w, gauss_coord,VzEnum);
    3904 
    3905                         D_scalar=gauss_weight*Jdet;
    3906 
    3907                         if(dt){
    3908                                 D_scalar=D_scalar*dt;
    3909                         }
    3910 
    3911                         D[0][0]=D_scalar*u;D[0][1]=0;         D[0][2]=0;
    3912                         D[1][0]=0;         D[1][1]=D_scalar*v;D[1][2]=0;
    3913                         D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar*w;
    3914 
    3915                         /*  Do the triple product B'*D*Bprime: */
    3916                         MatrixMultiply(&B_advec[0][0],3,numdof,1,&D[0][0],3,3,0,&tBD_advec[0][0],0);
    3917                         MatrixMultiply(&tBD_advec[0][0],numdof,3,0,&Bprime_advec[0][0],3,numdof,0,&Ke_gaussian_advec[0][0],0);
    3918 
    3919                         /*Transient: */
    3920                         if(dt){
    3921                                 GetNodalFunctions(&L[0], gauss_coord);
    3922                                 D_scalar=gauss_weight*Jdet;
    3923                                 D_scalar=D_scalar;
    3924 
    3925                                 /*  Do the triple product L'*D*L: */
    3926                                 MatrixMultiply(&L[0],numdof,1,0,&D_scalar,1,1,0,&tLD[0],0);
    3927                                 MatrixMultiply(&tLD[0],numdof,1,0,&L[0],1,numdof,0,&Ke_gaussian_transient[0][0],0);
    3928                         }
    3929                         else{
    3930                                 for(i=0;i<numdof;i++){
    3931                                         for(j=0;j<numdof;j++){
    3932                                                 Ke_gaussian_transient[i][j]=0;
    3933                                         }
    3934                                 }
    3935                         }
    3936 
    3937                         /*Artifficial diffusivity*/
    3938                         if(artdiff){
    3939                                 /*Build K: */
    3940                                 D_scalar=gauss_weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
    3941                                 if(dt){
    3942                                         D_scalar=D_scalar*dt;
    3943                                 }
    3944                                 K[0][0]=D_scalar*pow(u,2);       K[0][1]=D_scalar*fabs(u)*fabs(v);
    3945                                 K[1][0]=D_scalar*fabs(u)*fabs(v);K[1][1]=D_scalar*pow(v,2);
    3946 
    3947                                 /*Get B_artdiff: */
    3948                                 GetB_artdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss_coord);
    3949 
    3950                                 /*  Do the triple product B'*K*B: */
    3951                                 MatrixMultiply(&B_artdiff[0][0],2,numdof,1,&K[0][0],2,2,0,&tBD_artdiff[0][0],0);
    3952                                 MatrixMultiply(&tBD_artdiff[0][0],numdof,2,0,&B_artdiff[0][0],2,numdof,0,&Ke_gaussian_artdiff[0][0],0);
    3953                         }
    3954                         else{
    3955                                 for(i=0;i<numdof;i++){
    3956                                         for(j=0;j<numdof;j++){
    3957                                                 Ke_gaussian_artdiff[i][j]=0;
    3958                                         }
    3959                                 }
    3960                         }
    3961 
    3962                         /*Add Ke_gaussian to pKe: */
    3963                         for(i=0;i<numdof;i++){
    3964                                 for(j=0;j<numdof;j++){
    3965                                         K_terms[i][j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
    3966                                 }
    3967                         }
    3968                 }
    3969         }
    3970 
    3971         /*Add Ke_gg to global matrix Kgg: */
    3972         MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)K_terms,ADD_VALUES);
    3973 
    3974         xfree((void**)&first_gauss_area_coord);
    3975         xfree((void**)&second_gauss_area_coord);
    3976         xfree((void**)&third_gauss_area_coord);
    3977         xfree((void**)&area_gauss_weights);
    3978         xfree((void**)&vert_gauss_weights);
    3979         xfree((void**)&vert_gauss_coord);
    3980 
    3981         //Ice/ocean heat exchange flux on ice shelf base
    3982         if(onbed && shelf){
    3983 
    3984                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    3985                 tria->CreateKMatrixThermal(Kgg);
    3986                 delete tria;
    3987         }
    3988 }
    3989 /*}}}*/
    3990 /*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
    3991 void Penta::CreatePVectorBalancedthickness( Vec pg){
    3992 
    3993         /*Collapsed formulation: */
    3994         Tria*  tria=NULL;
    3995 
    3996         /*flags: */
    3997         bool onbed;
    3998         bool onwater;
    3999 
    4000         /*recover some inputs: */
    4001         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4002         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4003 
    4004         /*If on water, skip: */
    4005         if(onwater)return;
    4006 
    4007         /*Is this element on the bed? :*/
    4008         if(!onbed)return;
    4009 
    4010         /*Spawn Tria element from the base of the Penta: */
    4011         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4012         tria->CreatePVector(pg);
    4013         delete tria;
    4014         return;
    4015 }
    4016 /*}}}*/
    4017 /*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
    4018 void Penta::CreatePVectorBalancedvelocities( Vec pg){
    4019 
    4020         /*Collapsed formulation: */
    4021         Tria*  tria=NULL;
    4022 
    4023         /*flags: */
    4024         bool onbed;
    4025         bool onwater;
    4026 
    4027         /*recover some inputs: */
    4028         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4029         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4030 
    4031         /*If on water, skip: */
    4032         if(onwater)return;
    4033 
    4034         /*Is this element on the bed? :*/
    4035         if(!onbed)return;
    4036 
    4037         /*Spawn Tria element from the base of the Penta: */
    4038         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4039         tria->CreatePVector(pg);
    4040         delete tria;
    4041         return;
    4042 }
    4043 /*}}}*/
    4044 /*FUNCTION Penta::CreatePVectorDiagnosticHoriz {{{1*/
    4045 void Penta::CreatePVectorDiagnosticHoriz( Vec pg){
    4046 
    4047         int i,j;
    4048 
    4049         /* node data: */
    4050         const int    numgrids=6;
    4051         const int    NDOF2=2;
    4052         const int    numdof=NDOF2*numgrids;
    4053         double       xyz_list[numgrids][3];
    4054         int          doflist[numdof];
    4055         int          numberofdofspernode;
    4056 
    4057         /* parameters: */
    4058         double  slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
    4059         double  driving_stress_baseline;
    4060         double  thickness;
    4061 
    4062         /* gaussian points: */
    4063         int     num_gauss,ig;
    4064         double* first_gauss_area_coord  =  NULL;
    4065         double* second_gauss_area_coord =  NULL;
    4066         double* third_gauss_area_coord  =  NULL;
    4067         double* fourth_gauss_vert_coord  =  NULL;
    4068         double* area_gauss_weights      =  NULL;
    4069         double* vert_gauss_weights      =  NULL;
    4070         double  gauss_coord[4];
    4071         int     order_area_gauss;
    4072         int     num_vert_gauss;
    4073         int     num_area_gauss;
    4074         int     ig1,ig2;
    4075         double  gauss_weight1,gauss_weight2;
    4076         double  gauss_weight;
    4077 
    4078         /* Jacobian: */
    4079         double Jdet;
    4080 
    4081         /*nodal functions: */
    4082         double l1l6[6];
    4083 
    4084         /*element vector at the gaussian points: */
    4085         double  pe_g[numdof]={0.0};
    4086         double  pe_g_gaussian[numdof];
    4087 
    4088         /*Spawning: */
    4089         Tria* tria=NULL;
    4090 
    4091         /*inputs: */
    4092         bool onwater;
    4093         bool collapse;
    4094         bool onbed;
    4095         Input* surface_input=NULL;
    4096         Input* thickness_input=NULL;
    4097 
    4098         /*retrieve inputs :*/
    4099         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4100         inputs->GetParameterValue(&collapse,CollapseEnum);
    4101         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4102 
    4103         /*If on water, skip load: */
    4104         if(onwater)return;
    4105 
    4106         /*Figure out if this pentaelem is collapsed. If so, then bailout, except if it is at the
    4107           bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build
    4108           the load vector. */
    4109 
    4110         if ((collapse==1) && (onbed==0)){
    4111                 /*This element should be collapsed, but this element is not on the bedrock, therefore all its
    4112                  * dofs have already been frozen! Do nothing: */
    4113                 return;
    4114         }
    4115         else if ((collapse==1) && (onbed==1)){
    4116 
    4117                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    4118                  *and use its CreatePVector functionality to return an elementary load vector: */
    4119                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4120                 tria->CreatePVector(pg);
    4121                 delete tria;
    4122                 return;
    4123         }
    4124         else{
    4125 
    4126                 /*Implement standard penta element: */
    4127 
    4128                 /* Get node coordinates and dof list: */
    4129                 GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    4130                 GetDofList(&doflist[0],&numberofdofspernode);
    4131 
    4132                 /*Get gaussian points and weights :*/
    4133                 order_area_gauss=2;
    4134                 num_vert_gauss=3;
    4135 
    4136                 GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
    4137 
    4138                 /*Retrieve all inputs we will be needing: */
    4139                 thickness_input=inputs->GetInput(ThicknessEnum);
    4140                 surface_input=inputs->GetInput(SurfaceEnum);
    4141 
    4142                 /* Start  looping on the number of gaussian points: */
    4143                 for (ig1=0; ig1<num_area_gauss; ig1++){
    4144                         for (ig2=0; ig2<num_vert_gauss; ig2++){
    4145 
    4146                                 /*Pick up the gaussian point: */
    4147                                 gauss_weight1=*(area_gauss_weights+ig1);
    4148                                 gauss_weight2=*(vert_gauss_weights+ig2);
    4149                                 gauss_weight=gauss_weight1*gauss_weight2;
    4150 
    4151                                 gauss_coord[0]=*(first_gauss_area_coord+ig1);
    4152                                 gauss_coord[1]=*(second_gauss_area_coord+ig1);
    4153                                 gauss_coord[2]=*(third_gauss_area_coord+ig1);
    4154                                 gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
    4155 
    4156                                 /*Compute thickness at gaussian point: */
    4157                                 thickness_input->GetParameterValue(&thickness, gauss_coord);
    4158 
    4159                                 /*Compute slope at gaussian point: */
    4160                                 surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss_coord);
    4161 
    4162                                 /* Get Jacobian determinant: */
    4163                                 GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    4164 
    4165                                 /*Get nodal functions: */
    4166                                 GetNodalFunctions(l1l6, gauss_coord);
    4167 
    4168                                 /*Compute driving stress: */
    4169                                 driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
    4170 
    4171                                 /*Build pe_g_gaussian vector: */
    4172                                 for (i=0;i<numgrids;i++){
    4173                                         for (j=0;j<NDOF2;j++){
    4174                                                 pe_g_gaussian[i*NDOF2+j]=-driving_stress_baseline*slope[j]*Jdet*gauss_weight*l1l6[i];
    4175                                         }
    4176                                 }
    4177 
    4178                                 /*Add pe_g_gaussian vector to pe_g: */
    4179                                 for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
    4180 
    4181                         } //for (ig2=0; ig2<num_vert_gauss; ig2++)
    4182                 } //for (ig1=0; ig1<num_area_gauss; ig1++)
    4183 
    4184         } //else if ((collapse==1) && (onbed==1))
    4185 
    4186         /*Add pe_g to global vector pg: */
    4187         VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
    4188 
    4189         xfree((void**)&first_gauss_area_coord);
    4190         xfree((void**)&second_gauss_area_coord);
    4191         xfree((void**)&third_gauss_area_coord);
    4192         xfree((void**)&fourth_gauss_vert_coord);
    4193         xfree((void**)&area_gauss_weights);
    4194         xfree((void**)&vert_gauss_weights);
    4195 
    4196 }
    4197 /*}}}*/
    4198 /*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
    4199 void  Penta::CreatePVectorAdjointHoriz(Vec p_g){
    4200 
    4201         int i;
    4202         Tria* tria=NULL;
    4203 
    4204         /*inputs: */
    4205         bool onwater;
    4206         bool collapse;
    4207         bool onsurface;
    4208         bool onbed;
    4209 
    4210         /*retrieve inputs :*/
    4211         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4212         inputs->GetParameterValue(&collapse,CollapseEnum);
    4213         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4214         inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
    4215 
    4216         /*If on water, skip: */
    4217         if(onwater) return;
    4218 
    4219         /*Bail out if this element if:
    4220          * -> Non collapsed and not on the surface
    4221          * -> collapsed (2d model) and not on bed) */
    4222         if ((!collapse && !onsurface) || (collapse && !onbed)){
    4223                 return;
    4224         }
    4225         else if (collapse){
    4226 
    4227                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    4228                  * and compute pe_g*/
    4229                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    4230                 tria->CreatePVectorAdjointHoriz(p_g);
    4231                 delete tria;
    4232                 return;
    4233         }
    4234         else{
    4235 
    4236                 tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    4237                 tria->CreatePVectorAdjointHoriz(p_g);
    4238                 delete tria;
    4239                 return;
    4240         }
    4241 }
    4242 /*}}}*/
    4243 /*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
    4244 void  Penta::CreatePVectorDiagnosticHutter(Vec pg){
    4245 
    4246         /*Collapsed formulation: */
    4247         Beam*  beam=NULL;
    4248         int    i;
    4249 
    4250         /*flags: */
    4251         bool onwater;
    4252 
    4253         /*recover some inputs: */
    4254         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4255 
    4256         /*If on water, skip: */
    4257         if(onwater)return;
    4258 
    4259         /*Spawn 3 beam elements: */
    4260         for(i=0;i<3;i++){
    4261                 beam=(Beam*)SpawnBeam(i,i+3); //[0 3], [1 4] and [2 5] are the four vertical edges of the Penta
    4262                 beam->CreatePVector(pg);
    4263         }
    4264 
    4265         /*clean up*/
    4266         delete beam;
    4267 
    4268 }
    4269 /*}}}*/
    4270 /*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
    4271 void Penta::CreatePVectorDiagnosticStokes( Vec pg){
    4272 
    4273         /*indexing: */
    4274         int i,j;
    4275 
    4276         const int numgrids=6;
    4277         const int DOFPERGRID=4;
    4278         const int numdof=numgrids*DOFPERGRID;
    4279         const int numgrids2d=3;
    4280         int numdof2d=numgrids2d*DOFPERGRID;
    4281         int doflist[numdof];
    4282         int numberofdofspernode;
    4283 
    4284         /*Material properties: */
    4285         double         gravity,rho_ice,rho_water;
    4286 
    4287         /*parameters: */
    4288         double             xyz_list_tria[numgrids2d][3];
    4289         double         xyz_list[numgrids][3];
    4290         double             surface_normal[3];
    4291         double             bed_normal[3];
    4292         double         bed;
    4293 
    4294         /* gaussian points: */
    4295         int     num_area_gauss;
    4296         int     igarea,igvert;
    4297         double* first_gauss_area_coord  =  NULL;
    4298         double* second_gauss_area_coord =  NULL;
    4299         double* third_gauss_area_coord  =  NULL;
    4300         double* vert_gauss_coord = NULL;
    4301         double* area_gauss_weights  =  NULL;
    4302         double* vert_gauss_weights  =  NULL;
    4303 
    4304         /* specific gaussian point: */
    4305         double  gauss_weight,area_gauss_weight,vert_gauss_weight;
    4306         double  gauss_coord[4];
    4307         double  gauss_coord_tria[3];
    4308 
    4309         int     area_order=5;
    4310         int       num_vert_gauss=5;
    4311 
    4312         double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
    4313         double  viscosity;
    4314         double  water_pressure;
    4315         int     dofs[3]={0,1,2};
    4316 
    4317         /*matrices: */
    4318         double     Pe_temp[27]={0.0}; //for the six nodes and the bubble
    4319         double     Pe_gaussian[27]={0.0}; //for the six nodes and the bubble
    4320         double     Ke_temp[27][3]={0.0}; //for the six nodes and the bubble
    4321         double     Pe_reduced[numdof]; //for the six nodes only
    4322         double     Ke_gaussian[27][3];
    4323         double     L[3]; //for the three nodes of the bed
    4324         double     l1l7[7]; //for the six nodes and the bubble
    4325         double     B[8][27];
    4326         double     B_prime[8][27];
    4327         double     B_prime_bubble[8][3];
    4328         double     Jdet;
    4329         double     Jdet2d;
    4330         double     D[8][8]={0.0};
    4331         double     D_scalar;
    4332         double     tBD[27][8];
    4333         double     P_terms[numdof]={0.0};
    4334 
    4335         Tria*            tria=NULL;
    4336 
    4337         /*parameters: */
    4338         double stokesreconditioning;
    4339 
    4340         /*inputs: */
    4341         bool onwater;
    4342         bool onbed;
    4343         bool shelf;
    4344         bool isstokes;
    4345         Input* vx_input=NULL;
    4346         Input* vy_input=NULL;
    4347         Input* vz_input=NULL;
    4348         Input* bed_input=NULL;
    4349 
    4350         /*retrieve inputs :*/
    4351         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4352         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4353         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    4354         inputs->GetParameterValue(&isstokes,IsStokesEnum);
    4355 
    4356         /*retrieve some parameters: */
    4357         this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
    4358 
    4359         /*If on water or not Stokes, skip load: */
    4360         if(onwater || !isstokes) return;
    4361 
    4362         /*If on water, skip load: */
    4363         if(onwater)return;
    4364 
    4365         /*recovre material parameters: */
    4366         rho_water=matpar->GetRhoWater();
    4367         rho_ice=matpar->GetRhoIce();
    4368         gravity=matpar->GetG();
    4369 
    4370         /* Get node coordinates and dof list: */
    4371         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    4372         GetDofList(&doflist[0],&numberofdofspernode);
    4373 
    4374         /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    4375                 get tria gaussian points as well as segment gaussian points. For tria gaussian
    4376                 points, order of integration is 2, because we need to integrate the product tB*D*B'
    4377                 which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    4378                 points, same deal, which yields 3 gaussian points.*/
    4379 
    4380         /* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
    4381         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
    4382 
    4383         /*Retrieve all inputs we will be needing: */
    4384         vx_input=inputs->GetInput(VxEnum);
    4385         vy_input=inputs->GetInput(VyEnum);
    4386         vz_input=inputs->GetInput(VzEnum);
    4387         bed_input=inputs->GetInput(BedEnum);
    4388 
    4389         /* Start  looping on the number of gaussian points: */
    4390         for (igarea=0; igarea<num_area_gauss; igarea++){
    4391                 for (igvert=0; igvert<num_vert_gauss; igvert++){
    4392                         /*Pick up the gaussian point: */
    4393                         area_gauss_weight=*(area_gauss_weights+igarea);
    4394                         vert_gauss_weight=*(vert_gauss_weights+igvert);
    4395                         gauss_weight=area_gauss_weight*vert_gauss_weight;
    4396                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    4397                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    4398                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    4399                         gauss_coord[3]=*(vert_gauss_coord+igvert);
    4400 
    4401                         /*Compute strain rate and viscosity: */
    4402                         this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
    4403                         matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    4404 
    4405                         /* Get Jacobian determinant: */
    4406                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    4407 
    4408                         /* Get nodal functions */
    4409                         GetNodalFunctionsStokes(&l1l7[0], gauss_coord);
    4410 
    4411                         /* Build gaussian vector */
    4412                         for(i=0;i<numgrids+1;i++){
    4413                                 Pe_gaussian[i*DOFPERGRID+2]=-rho_ice*gravity*Jdet*gauss_weight*l1l7[i];
    4414                         }
    4415 
    4416                         /*Add Pe_gaussian to terms in Pe_temp. Watch out for column orientation from matlab: */
    4417                         for(i=0;i<27;i++){
    4418                                 Pe_temp[i]+=Pe_gaussian[i];
    4419                         }
    4420 
    4421                         /*Get B and Bprime matrices: */
    4422                         GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord);
    4423                         GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord);
    4424 
    4425                         /*Get bubble part of Bprime */
    4426                         for(i=0;i<8;i++){
    4427                                 for(j=0;j<3;j++){
    4428                                         B_prime_bubble[i][j]=B_prime[i][j+24];
    4429                                 }
    4430                         }
    4431 
    4432                         /* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant
    4433                          * onto this scalar matrix, so that we win some computational time: */
    4434                         D_scalar=gauss_weight*Jdet;
    4435                         for (i=0;i<6;i++){
    4436                                 D[i][i]=D_scalar*viscosity;
    4437                         }
    4438                         for (i=6;i<8;i++){
    4439                                 D[i][i]=-D_scalar*stokesreconditioning;
    4440                         }
    4441 
    4442                         /*  Do the triple product tB*D*Bprime: */
    4443                         MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
    4444                         MatrixMultiply(&tBD[0][0],27,8,0,&B_prime_bubble[0][0],8,3,0,&Ke_gaussian[0][0],0);
    4445 
    4446                         /*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
    4447                         for(i=0;i<27;i++){
    4448                                 for(j=0;j<3;j++){
    4449                                         Ke_temp[i][j]+=Ke_gaussian[i][j];
    4450                                 }
    4451                         }
    4452                 }
    4453         }
    4454 
    4455         /*Deal with 2d friction at the bedrock interface: */
    4456         if ( (onbed==1) && (shelf==1)){
    4457 
    4458                 for(i=0;i<numgrids2d;i++){
    4459                         for(j=0;j<3;j++){
    4460                                 xyz_list_tria[i][j]=xyz_list[i][j];
    4461                         }
    4462                 }
    4463 
    4464                 xfree((void**)&first_gauss_area_coord); xfree((void**)&second_gauss_area_coord); xfree((void**)&third_gauss_area_coord); xfree((void**)&area_gauss_weights);
    4465                 GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
    4466 
    4467                 /* Start looping on the number of gauss 2d (nodes on the bedrock) */
    4468                 for (igarea=0; igarea<num_area_gauss; igarea++){
    4469                         gauss_weight=*(area_gauss_weights+igarea);
    4470                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    4471                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    4472                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    4473                         gauss_coord[3]=-1;
    4474 
    4475                         gauss_coord_tria[0]=*(first_gauss_area_coord+igarea);
    4476                         gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
    4477                         gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
    4478 
    4479                         /*Get the Jacobian determinant */
    4480                         tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
    4481 
    4482                         /* Get bed at gaussian point */
    4483                         bed_input->GetParameterValue(&bed, gauss_coord);
    4484 
    4485                         /*Get L matrix : */
    4486                         tria->GetL(&L[0], &xyz_list[0][0], gauss_coord_tria,1);
    4487 
    4488                         /*Get water_pressure at gaussian point */
    4489                         water_pressure=gravity*rho_water*bed;
    4490 
    4491                         /*Get normal vecyor to the bed */
    4492                         SurfaceNormal(&surface_normal[0],xyz_list_tria);
    4493 
    4494                         bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
    4495                         bed_normal[1]=-surface_normal[1];
    4496                         bed_normal[2]=-surface_normal[2];
    4497 
    4498                         for(i=0;i<numgrids2d;i++){
    4499                                 for(j=0;j<3;j++){
    4500                                         Pe_temp[i*DOFPERGRID+j]+=water_pressure*gauss_weight*Jdet2d*L[i]*bed_normal[j];
    4501                                 }
    4502                         }
    4503                 }
    4504         } //if ( (onbed==1) && (shelf==1))
    4505 
    4506         /*Reduce the matrix */
    4507         ReduceVectorStokes(&Pe_reduced[0], &Ke_temp[0][0], &Pe_temp[0]);
    4508 
    4509         for(i=0;i<numdof;i++){
    4510                 P_terms[i]+=Pe_reduced[i];
    4511         }
    4512 
    4513         /*Add P_terms to global vector pg: */
    4514         VecSetValues(pg,numdof,doflist,(const double*)P_terms,ADD_VALUES);
    4515 
    4516         /*Free ressources:*/
    4517         xfree((void**)&first_gauss_area_coord);
    4518         xfree((void**)&second_gauss_area_coord);
    4519         xfree((void**)&third_gauss_area_coord);
    4520         xfree((void**)&area_gauss_weights);
    4521         xfree((void**)&vert_gauss_coord);
    4522         xfree((void**)&vert_gauss_weights);
    4523 
    4524 }
    4525 /*}}}*/
    4526 /*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
    4527 void  Penta::CreatePVectorAdjointStokes(Vec p_g){
    4528 
    4529         int i;
    4530         Tria* tria=NULL;
    4531 
    4532         /*inputs: */
    4533         bool onwater;
    4534         bool onsurface;
    4535 
    4536         /*retrieve inputs :*/
    4537         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4538         inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
    4539 
    4540         /*If on water, skip: */
    4541         if(onwater || !onsurface)return;
    4542 
    4543         /*Call Tria's function*/
    4544         tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
    4545         tria->CreatePVectorAdjointStokes(p_g);
    4546         delete tria;
    4547         return;
    4548 }
    4549 /*}}}*/
    4550 /*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
    4551 void  Penta::CreatePVectorDiagnosticVert( Vec pg){
    4552 
    4553         int i;
    4554 
    4555         /* node data: */
    4556         const int    numgrids=6;
    4557         const int    NDOF1=1;
    4558         const int    numdof=NDOF1*numgrids;
    4559         double       xyz_list[numgrids][3];
    4560         int          doflist[numdof];
    4561         int          numberofdofspernode;
    4562 
    4563         /* gaussian points: */
    4564         int     num_gauss,ig;
    4565         double* first_gauss_area_coord  =  NULL;
    4566         double* second_gauss_area_coord =  NULL;
    4567         double* third_gauss_area_coord  =  NULL;
    4568         double* fourth_gauss_vert_coord  =  NULL;
    4569         double* area_gauss_weights      =  NULL;
    4570         double* vert_gauss_weights      =  NULL;
    4571         double  gauss_coord[4];
    4572         int     order_area_gauss;
    4573         int     num_vert_gauss;
    4574         int     num_area_gauss;
    4575         int     ig1,ig2;
    4576         double  gauss_weight1,gauss_weight2;
    4577         double  gauss_weight;
    4578 
    4579         /* Jacobian: */
    4580         double Jdet;
    4581 
    4582         /*element vector at the gaussian points: */
    4583         double  pe_g[numdof]={0.0};
    4584         double  pe_g_gaussian[numdof];
    4585         double l1l6[6];
    4586 
    4587         /*Spawning: */
    4588         Tria* tria=NULL;
    4589 
    4590         /*input parameters for structural analysis (diagnostic): */
    4591         double du[3];
    4592         double dv[3];
    4593         double dudx,dvdy;
    4594         int     dofs1[1]={0};
    4595         int     dofs2[1]={1};
    4596 
    4597         /*inputs: */
    4598         bool onwater;
    4599         bool onbed;
    4600         Input* vx_input=NULL;
    4601         Input* vy_input=NULL;
    4602 
    4603         /*retrieve inputs :*/
    4604         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4605         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4606 
    4607         /*If on water, skip: */
    4608         if(onwater)return;
    4609 
    4610         /*If we are on the bedrock, spawn a tria on the bedrock, and use it to build the
    4611          *diagnostic base vertical stifness: */
    4612         if(onbed){
    4613                 tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 are on the bedrock
    4614                 tria->CreatePVectorDiagnosticBaseVert(pg);
    4615                 delete tria;
    4616         }
    4617 
    4618         /*Now, handle the standard penta element: */
    4619         /* Get node coordinates and dof list: */
    4620         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    4621         GetDofList(&doflist[0],&numberofdofspernode);
    4622 
    4623         /*Get gaussian points and weights :*/
    4624         order_area_gauss=2;
    4625         num_vert_gauss=2;
    4626 
    4627         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, &fourth_gauss_vert_coord,&vert_gauss_weights,order_area_gauss,num_vert_gauss);
    4628 
    4629         /*Retrieve all inputs we will be needing: */
    4630         vx_input=inputs->GetInput(VxEnum);
    4631         vy_input=inputs->GetInput(VyEnum);
    4632 
    4633         /* Start  looping on the number of gaussian points: */
    4634         for (ig1=0; ig1<num_area_gauss; ig1++){
    4635                 for (ig2=0; ig2<num_vert_gauss; ig2++){
    4636 
    4637                         /*Pick up the gaussian point: */
    4638                         gauss_weight1=*(area_gauss_weights+ig1);
    4639                         gauss_weight2=*(vert_gauss_weights+ig2);
    4640                         gauss_weight=gauss_weight1*gauss_weight2;
    4641 
    4642                         gauss_coord[0]=*(first_gauss_area_coord+ig1);
    4643                         gauss_coord[1]=*(second_gauss_area_coord+ig1);
    4644                         gauss_coord[2]=*(third_gauss_area_coord+ig1);
    4645                         gauss_coord[3]=*(fourth_gauss_vert_coord+ig2);
    4646 
    4647                         /*Get velocity derivative, with respect to x and y: */
    4648 
    4649                         vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss_coord);
    4650                         vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss_coord);
    4651                         dudx=du[0];
    4652                         dvdy=dv[1];
    4653 
    4654                         /* Get Jacobian determinant: */
    4655                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    4656 
    4657                         /*Get nodal functions: */
    4658                         GetNodalFunctions(l1l6, gauss_coord);
    4659 
    4660                         /*Build pe_g_gaussian vector: */
    4661                         for (i=0;i<numgrids;i++){
    4662                                 pe_g_gaussian[i]=(dudx+dvdy)*Jdet*gauss_weight*l1l6[i];
    4663                         }
    4664 
    4665                         /*Add pe_g_gaussian vector to pe_g: */
    4666                         for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
    4667 
    4668                 } //for (ig2=0; ig2<num_vert_gauss; ig2++)
    4669         } //for (ig1=0; ig1<num_area_gauss; ig1++)
    4670 
    4671         /*Add pe_g to global vector pg: */
    4672         VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
    4673 
    4674         xfree((void**)&first_gauss_area_coord);
    4675         xfree((void**)&second_gauss_area_coord);
    4676         xfree((void**)&third_gauss_area_coord);
    4677         xfree((void**)&fourth_gauss_vert_coord);
    4678         xfree((void**)&area_gauss_weights);
    4679         xfree((void**)&vert_gauss_weights);
    4680 }
    4681 /*}}}*/
    4682 /*FUNCTION Penta::CreatePVectorMelting {{{1*/
    4683 void Penta::CreatePVectorMelting( Vec pg){
    4684         return;
    4685 }
    4686 /*}}}*/
    4687 /*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
    4688 
    4689 void Penta::CreatePVectorPrognostic( Vec pg){
    4690 
    4691         /*Collapsed formulation: */
    4692         Tria*  tria=NULL;
    4693 
    4694         /*inputs: */
    4695         bool onwater;
    4696         bool onbed;
    4697 
    4698         /*retrieve inputs :*/
    4699         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4700         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4701        
    4702         /*If on water, skip: */
    4703         if(onwater)return;
    4704 
    4705         /*Is this element on the bed? :*/
    4706         if(!onbed)return;
    4707 
    4708         /*Spawn Tria element from the base of the Penta: */
    4709         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4710         tria->CreatePVector(pg);
    4711         delete tria;
    4712         return;
    4713 }
    4714 /*}}}*/
    4715 /*FUNCTION Penta::CreatePVectorSlope {{{1*/
    4716 
    4717 void Penta::CreatePVectorSlope( Vec pg){
    4718 
    4719         /*Collapsed formulation: */
    4720         Tria*  tria=NULL;
    4721 
    4722         /*inputs: */
    4723         bool onwater;
    4724         bool onbed;
    4725 
    4726         /*retrieve inputs :*/
    4727         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4728         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4729 
    4730         /*If on water, skip: */
    4731         if(onwater)return;
    4732 
    4733         /*Is this element on the bed? :*/
    4734         if(!onbed)return;
    4735 
    4736         /*Spawn Tria element from the base of the Penta: */
    4737         tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4738         tria->CreatePVector(pg);
    4739         delete tria;
    4740         return;
    4741 }
    4742 /*}}}*/
    4743 /*FUNCTION Penta::CreatePVectorThermal {{{1*/
    4744 void Penta::CreatePVectorThermal( Vec pg){
    4745 
    4746         /*indexing: */
    4747         int i,j;
    4748         int found=0;
    4749 
    4750         const int  numgrids=6;
    4751         const int  NDOF1=1;
    4752         const int  numdof=numgrids*NDOF1;
    4753         int        doflist[numdof];
    4754         int        numberofdofspernode;
    4755 
    4756         /*Grid data: */
    4757         double        xyz_list[numgrids][3];
    4758 
    4759         /* gaussian points: */
    4760         int     num_area_gauss,igarea,igvert;
    4761         double* first_gauss_area_coord  =  NULL;
    4762         double* second_gauss_area_coord =  NULL;
    4763         double* third_gauss_area_coord  =  NULL;
    4764         double* vert_gauss_coord = NULL;
    4765         double* area_gauss_weights  =  NULL;
    4766         double* vert_gauss_weights  =  NULL;
    4767         double  gauss_weight,area_gauss_weight,vert_gauss_weight;
    4768         double  gauss_coord[4];
    4769         int     area_order=2;
    4770         int       num_vert_gauss=3;
    4771 
    4772         double temperature_list[numgrids];
    4773         double temperature;
    4774 
    4775         /*Material properties: */
    4776         double gravity,rho_ice,rho_water;
    4777         double mixed_layer_capacity,heatcapacity;
    4778         double beta,meltingpoint,thermal_exchange_velocity;
    4779 
    4780         /* element parameters: */
    4781         int    friction_type;
    4782 
    4783         int    dofs[3]={0,1,2};
    4784         int    dofs1[1]={0};
    4785 
    4786         /*matrices: */
    4787         double P_terms[numdof]={0.0};
    4788         double L[numdof];
    4789         double l1l2l3[3];
    4790         double alpha2_list[3];
    4791         double basalfriction_list[3]={0.0};
    4792         double basalfriction;
    4793         double epsilon[6];
    4794         double epsilon_sqr[3][3];
    4795         double epsilon_matrix[3][3];
    4796 
    4797         double Jdet;
    4798         double viscosity;
    4799         double epsilon_eff;
    4800         double phi;
    4801         double t_pmp;
    4802         double scalar;
    4803         double scalar_def;
    4804         double scalar_ocean;
    4805         double scalar_transient;
    4806 
    4807         /*Collapsed formulation: */
    4808         Tria*  tria=NULL;
    4809 
    4810         /*parameters: */
    4811         double dt;
    4812 
    4813         /*inputs: */
    4814         bool onwater;
    4815         bool onbed;
    4816         bool shelf;
    4817         Input* vx_input=NULL;
    4818         Input* vy_input=NULL;
    4819         Input* vz_input=NULL;
    4820 
    4821         /*retrieve inputs :*/
    4822         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    4823         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4824         inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
    4825 
    4826         /*retrieve some parameters: */
    4827         this->parameters->FindParam(&dt,DtEnum);
    4828 
    4829         /*If on water, skip: */
    4830         if(onwater)return;
    4831 
    4832         /* Get node coordinates and dof list: */
    4833         GetVerticesCoordinates(&xyz_list[0][0], nodes, numgrids);
    4834         GetDofList(&doflist[0],&numberofdofspernode);
    4835 
    4836         /*recovre material parameters: */
    4837         rho_water=matpar->GetRhoWater();
    4838         rho_ice=matpar->GetRhoIce();
    4839         gravity=matpar->GetG();
    4840         heatcapacity=matpar->GetHeatCapacity();
    4841         beta=matpar->GetBeta();
    4842         meltingpoint=matpar->GetMeltingPoint();
    4843 
    4844         /* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore
    4845                 get tria gaussian points as well as segment gaussian points. For tria gaussian
    4846                 points, order of integration is 2, because we need to integrate the product tB*D*B'
    4847                 which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian
    4848                 points, same deal, which yields 3 gaussian points.: */
    4849 
    4850         /*Get gaussian points: */
    4851         GaussPenta( &num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights,&vert_gauss_coord, &vert_gauss_weights, area_order, num_vert_gauss);
    4852 
    4853         /*Retrieve all inputs we will be needing: */
    4854         vx_input=inputs->GetInput(VxEnum);
    4855         vy_input=inputs->GetInput(VyEnum);
    4856         vz_input=inputs->GetInput(VzEnum);
    4857 
    4858         /* Start  looping on the number of gaussian points: */
    4859         for (igarea=0; igarea<num_area_gauss; igarea++){
    4860                 for (igvert=0; igvert<num_vert_gauss; igvert++){
    4861                         /*Pick up the gaussian point: */
    4862                         area_gauss_weight=*(area_gauss_weights+igarea);
    4863                         vert_gauss_weight=*(vert_gauss_weights+igvert);
    4864                         gauss_weight=area_gauss_weight*vert_gauss_weight;
    4865                         gauss_coord[0]=*(first_gauss_area_coord+igarea);
    4866                         gauss_coord[1]=*(second_gauss_area_coord+igarea);
    4867                         gauss_coord[2]=*(third_gauss_area_coord+igarea);
    4868                         gauss_coord[3]=*(vert_gauss_coord+igvert);
    4869 
    4870                         /*Compute strain rate and viscosity: */
    4871                         this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss_coord,vx_input,vy_input,vz_input);
    4872                         matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
    4873 
    4874                         /* Get Jacobian determinant: */
    4875                         GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
    4876 
    4877                         /* Get nodal functions */
    4878                         GetNodalFunctions(&L[0], gauss_coord);
    4879 
    4880                         /*Build deformational heating: */
    4881                         GetPhi(&phi, &epsilon[0], viscosity);
    4882 
    4883                         /*Build pe_gaussian */
    4884                         scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss_weight;
    4885                         if(dt){
    4886                                 scalar_def=scalar_def*dt;
    4887                         }
    4888 
    4889                         for(i=0;i<numgrids;i++){
    4890                                 P_terms[i]+=scalar_def*L[i];
    4891                         }
    4892 
    4893                         /* Build transient now */
    4894                         if(dt){
    4895                                 inputs->GetParameterValue(&temperature, gauss_coord,TemperatureEnum);
    4896                                 scalar_transient=temperature*Jdet*gauss_weight;
    4897                                 for(i=0;i<numgrids;i++){
    4898                                         P_terms[i]+=scalar_transient*L[i];
    4899                                 }
    4900                         }
    4901                 }
    4902         }
    4903 
    4904         /*Add pe_g to global vector pg: */
    4905         VecSetValues(pg,numdof,doflist,(const double*)P_terms,ADD_VALUES);
    4906 
    4907         /* Ice/ocean heat exchange flux on ice shelf base */
    4908         if(onbed && shelf){
    4909 
    4910                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4911                 tria->CreatePVectorThermalShelf(pg);
    4912                 delete tria;
    4913         }
    4914 
    4915         /* Geothermal flux on ice sheet base and basal friction */
    4916         if(onbed && !shelf){
    4917 
    4918                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
    4919                 tria->CreatePVectorThermalSheet(pg);
    4920                 delete tria;
    4921         }
    4922         extern int my_rank;
    4923 
    4924         xfree((void**)&first_gauss_area_coord);
    4925         xfree((void**)&second_gauss_area_coord);
    4926         xfree((void**)&third_gauss_area_coord);
    4927         xfree((void**)&vert_gauss_coord);
    4928         xfree((void**)&area_gauss_weights);
    4929         xfree((void**)&vert_gauss_weights);
    4930 
    4931 }
    4932 /*}}}*/
    4933 /*FUNCTION Penta::VecExtrude {{{1*/
    4934 void  Penta::VecExtrude(Vec vector,double* vector_serial,int iscollapsed){
    4935 
    4936         /* node data: */
    4937         int   i;
    4938         Node* node=NULL;
    4939         int   extrude=0;
    4940 
    4941         /*inputs: */
    4942         bool collapse;
    4943         bool onbed;
    4944 
    4945         /*retrieve inputs :*/
    4946         inputs->GetParameterValue(&collapse,CollapseEnum);
    4947         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    4948 
    4949         /*Figure out if we should extrude for this element: */
    4950         if (iscollapsed){
    4951                 /*From higher level, we are told to extrude only elements that have the collapse flag on: */
    4952                 if (collapse)extrude=1;
    4953                 else extrude=0;
    4954         }
    4955         else{
    4956                 /*From higher level, we are told to extrude all elements: */
    4957                 extrude=1;
    4958         }
    4959 
    4960         /*Now, extrusion starts from the bed on, so double check this element is on
    4961          * the bedrock: */
    4962         if(onbed==0)extrude=0;
    4963 
    4964         /*Go on and extrude vector: */
    4965         if (extrude){
    4966 
    4967                 /* node data: */
    4968                 int          dof1;
    4969                 double       vectorel;
    4970 
    4971                 /*this penta is a collapsed macayeal. For each node on the base of this penta,
    4972                  * we grab the vector. Once we know the vector, we follow the upper nodes,
    4973                  * inserting the same vector value into vector, until we reach the surface: */
    4974                 for(i=0;i<3;i++){
    4975 
    4976                         node=nodes[i]; //base nodes
    4977                         dof1=node->GetDofList1();
    4978 
    4979                         /*get vector for this base node: */
    4980                         vectorel=vector_serial[dof1];
    4981 
    4982                         //go throvectorn all nodes which sit on top of this node, until we reach the surface,
    4983                         //and plvector  vector in vector
    4984                         for(;;){
    4985 
    4986                                 dof1=node->GetDofList1();
    4987                                 VecSetValues(vector,1,&dof1,&vectorel,INSERT_VALUES);
    4988 
    4989                                 if (node->IsOnSurface())break;
    4990                                 /*get next node: */
    4991                                 node=node->GetUpperNode();
    4992                         }
    4993                 }
    4994         }
    4995 }
    4996 /*}}}*/
    4997 /*FUNCTION Penta::InputExtrude {{{1*/
    4998 void  Penta::InputExtrude(int enum_type,bool only_if_collapsed){
    4999 
    5000         bool   onbed,collapse=false;
    5001         Penta *penta          = NULL;
    5002         Input *original_input = NULL;
    5003 
    5004         /*recover parameters: */
    5005         if (only_if_collapsed) inputs->GetParameterValue(&collapse,CollapseEnum);
    5006         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    5007 
    5008         /*First: if only_if_collapsed, check wether this penta is collapsed*/
    5009         if (only_if_collapsed && !collapse) return;
    5010 
    5011         /*Are we on the base, not on the surface?:*/
    5012         if(onbed){
    5013 
    5014                 /*OK, we are on bed. we will follow the steps:
    5015                  * 1: find input and extrude it.
    5016                  * 2: follow the upper element until we reach the surface
    5017                  * 3: for each element, we will add a copy of the extruded input*/
    5018 
    5019                 /*Step1: Extrude the original input: */
    5020                 original_input=(Input*)this->inputs->GetInput(enum_type);
    5021                 if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumAsString(enum_type));
    5022                 original_input->Extrude();
    5023 
    5024                 /*Stop if there is only one layer of element*/
    5025                 if (this->IsOnSurface()) return;
    5026 
    5027                 /*Step 2: this input has been extruded for this element, now follow the upper element*/
    5028                 penta=this;
    5029                 for(;;){
    5030 
    5031                         /* get upper Penta*/
    5032                         penta=penta->GetUpperElement();
    5033                         ISSMASSERT(penta->Id()!=this->id);
    5034 
    5035                         /*Add input of the basal element to penta->inputs*/
    5036                         Input* copy=NULL;
    5037                         copy=(Input*)original_input->copy();
    5038                         penta->inputs->AddInput((Input*)copy);
    5039 
    5040                         /*Stop if we have reached the surface*/
    5041                         if (penta->IsOnSurface()) break;
    5042 
    5043                 }
    5044         }
    5045 
    5046         return;
    5047 }
    5048 /*}}}*/
    5049 /*FUNCTION Penta::GetB {{{1*/
    5050 void Penta::GetB(double* B, double* xyz_list, double* gauss_coord){
    5051 
    5052         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2.
    5053          * For grid i, Bi can be expressed in the actual coordinate system
    5054          * by:
    5055          *       Bi=[ dh/dx          0      ]
    5056          *                [   0           dh/dy   ]
    5057          *                [ 1/2*dh/dy  1/2*dh/dx  ]
    5058          *                [ 1/2*dh/dz      0      ]
    5059          *                [  0         1/2*dh/dz  ]
    5060          * where h is the interpolation function for grid i.
    5061          *
    5062          * We assume B has been allocated already, of size: 5x(NDOF2*numgrids)
    5063          */
    5064 
    5065         int i;
    5066         const int numgrids=6;
    5067         const int NDOF3=3;
    5068         const int NDOF2=2;
    5069 
    5070         double dh1dh6[NDOF3][numgrids];
    5071 
    5072         /*Get dh1dh6 in actual coordinate system: */
    5073         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
    5074 
    5075         /*Build B: */
    5076         for (i=0;i<numgrids;i++){
    5077                 *(B+NDOF2*numgrids*0+NDOF2*i)=dh1dh6[0][i];
    5078                 *(B+NDOF2*numgrids*0+NDOF2*i+1)=0.0;
    5079 
    5080                 *(B+NDOF2*numgrids*1+NDOF2*i)=0.0;
    5081                 *(B+NDOF2*numgrids*1+NDOF2*i+1)=dh1dh6[1][i];
    5082 
    5083                 *(B+NDOF2*numgrids*2+NDOF2*i)=(float).5*dh1dh6[1][i];
    5084                 *(B+NDOF2*numgrids*2+NDOF2*i+1)=(float).5*dh1dh6[0][i];
    5085 
    5086                 *(B+NDOF2*numgrids*3+NDOF2*i)=(float).5*dh1dh6[2][i];
    5087                 *(B+NDOF2*numgrids*3+NDOF2*i+1)=0.0;
    5088 
    5089                 *(B+NDOF2*numgrids*4+NDOF2*i)=0.0;
    5090                 *(B+NDOF2*numgrids*4+NDOF2*i+1)=(float).5*dh1dh6[2][i];
    5091         }
    5092 
    5093 }
    5094 /*}}}*/
    5095 /*FUNCTION Penta::GetB_artdiff {{{1*/
    5096 void Penta::GetB_artdiff(double* B_artdiff, double* xyz_list, double* gauss_coord){
    5097 
    5098         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
    5099          * For grid i, Bi' can be expressed in the actual coordinate system
    5100          * by:
    5101          *       Bi_artdiff=[ dh/dx ]
    5102          *                       [ dh/dy ]
    5103          * where h is the interpolation function for grid i.
    5104          *
    5105          * We assume B has been allocated already, of size: 2x(DOFPERGRID*numgrids)
    5106          */
    5107 
    5108         int i;
    5109         const int calculationdof=3;
    5110         const int numgrids=6;
    5111         int DOFPERGRID=1;
    5112 
    5113         /*Same thing in the actual coordinate system: */
    5114         double dh1dh6[calculationdof][numgrids];
    5115 
    5116         /*Get dh1dh2dh3 in actual coordinates system : */
    5117         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list,gauss_coord);
    5118 
    5119         /*Build B': */
    5120         for (i=0;i<numgrids;i++){
    5121                 *(B_artdiff+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
    5122                 *(B_artdiff+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
    5123         }
    5124 }
    5125 /*}}}*/
    5126 /*FUNCTION Penta::GetB_advec {{{1*/
    5127 void Penta::GetB_advec(double* B_advec, double* xyz_list, double* gauss_coord){
    5128 
    5129         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
    5130          * For grid i, Bi' can be expressed in the actual coordinate system
    5131          * by:
    5132          *       Bi_advec =[ h ]
    5133          *                       [ h ]
    5134          *                       [ h ]
    5135          * where h is the interpolation function for grid i.
    5136          *
    5137          * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
    5138          */
    5139 
    5140         int i;
    5141         int calculationdof=3;
    5142         int numgrids=6;
    5143         int DOFPERGRID=1;
    5144 
    5145         /*Same thing in the actual coordinate system: */
    5146         double l1l6[6];
    5147 
    5148         /*Get dh1dh2dh3 in actual coordinates system : */
    5149         GetNodalFunctions(l1l6, gauss_coord);
    5150 
    5151         /*Build B': */
    5152         for (i=0;i<numgrids;i++){
    5153                 *(B_advec+DOFPERGRID*numgrids*0+DOFPERGRID*i)=l1l6[i];
    5154                 *(B_advec+DOFPERGRID*numgrids*1+DOFPERGRID*i)=l1l6[i];
    5155                 *(B_advec+DOFPERGRID*numgrids*2+DOFPERGRID*i)=l1l6[i];
    5156         }
    5157 }
    5158 /*}}}*/
    5159 /*FUNCTION Penta::GetB_conduct {{{1*/
    5160 void Penta::GetB_conduct(double* B_conduct, double* xyz_list, double* gauss_coord){
    5161 
    5162         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
    5163          * For grid i, Bi' can be expressed in the actual coordinate system
    5164          * by:
    5165          *       Bi_conduct=[ dh/dx ]
    5166          *                       [ dh/dy ]
    5167          *                       [ dh/dz ]
    5168          * where h is the interpolation function for grid i.
    5169          *
    5170          * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
    5171          */
    5172 
    5173         int i;
    5174         const int calculationdof=3;
    5175         const int numgrids=6;
    5176         int DOFPERGRID=1;
    5177 
    5178         /*Same thing in the actual coordinate system: */
    5179         double dh1dh6[calculationdof][numgrids];
    5180 
    5181         /*Get dh1dh2dh3 in actual coordinates system : */
    5182         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list,gauss_coord);
    5183 
    5184         /*Build B': */
    5185         for (i=0;i<numgrids;i++){
    5186                 *(B_conduct+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
    5187                 *(B_conduct+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
    5188                 *(B_conduct+DOFPERGRID*numgrids*2+DOFPERGRID*i)=dh1dh6[2][i];
    5189         }
    5190 }
    5191 /*}}}*/
    5192 /*FUNCTION Penta::GetB_vert {{{1*/
    5193 void Penta::GetB_vert(double* B, double* xyz_list, double* gauss_coord){
    5194 
    5195 
    5196         /*      Compute B  matrix. B=[dh1/dz dh2/dz dh3/dz dh4/dz dh5/dz dh6/dz];
    5197                 where hi is the interpolation function for grid i.*/
    5198 
    5199         int i;
    5200         const int NDOF3=3;
    5201         const int numgrids=6;
    5202         double dh1dh6[NDOF3][numgrids];
    5203 
    5204         /*Get dh1dh6 in actual coordinate system: */
    5205         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
    5206 
    5207         /*Build B: */
    5208         for (i=0;i<numgrids;i++){
    5209                 B[i]=dh1dh6[2][i]; 
    5210         }
    5211 
    5212 }
    5213 /*}}}*/
    5214 /*FUNCTION Penta::GetBPrime {{{1*/
    5215 void Penta::GetBPrime(double* B, double* xyz_list, double* gauss_coord){
    5216 
    5217         /*Compute B  prime matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2.
    5218          * For grid i, Bi can be expressed in the actual coordinate system
    5219          * by:
    5220          *       Bi=[ 2*dh/dx     dh/dy   ]
    5221          *                [   dh/dx    2*dh/dy  ]
    5222          *                [ dh/dy      dh/dx    ]
    5223          *                [ dh/dz         0     ]
    5224          *                [  0         dh/dz    ]
    5225          * where h is the interpolation function for grid i.
    5226          *
    5227          * We assume B has been allocated already, of size: 5x(NDOF2*numgrids)
    5228          */
    5229 
    5230         int i;
    5231         const int NDOF3=3;
    5232         const int NDOF2=2;
    5233         const int numgrids=6;
    5234 
    5235         double dh1dh6[NDOF3][numgrids];
    5236 
    5237         /*Get dh1dh6 in actual coordinate system: */
    5238         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
    5239 
    5240         /*Build BPrime: */
    5241         for (i=0;i<numgrids;i++){
    5242                 *(B+NDOF2*numgrids*0+NDOF2*i)=2.0*dh1dh6[0][i];
    5243                 *(B+NDOF2*numgrids*0+NDOF2*i+1)=dh1dh6[1][i];
    5244 
    5245                 *(B+NDOF2*numgrids*1+NDOF2*i)=dh1dh6[0][i];
    5246                 *(B+NDOF2*numgrids*1+NDOF2*i+1)=2.0*dh1dh6[1][i];
    5247 
    5248                 *(B+NDOF2*numgrids*2+NDOF2*i)=dh1dh6[1][i];
    5249                 *(B+NDOF2*numgrids*2+NDOF2*i+1)=dh1dh6[0][i];
    5250 
    5251                 *(B+NDOF2*numgrids*3+NDOF2*i)=dh1dh6[2][i];
    5252                 *(B+NDOF2*numgrids*3+NDOF2*i+1)=0.0;
    5253 
    5254                 *(B+NDOF2*numgrids*4+NDOF2*i)=0.0;
    5255                 *(B+NDOF2*numgrids*4+NDOF2*i+1)=dh1dh6[2][i];
    5256         }
    5257 }
    5258 /*}}}*/
    5259 /*FUNCTION Penta::GetBprime_advec {{{1*/
    5260 void Penta::GetBprime_advec(double* Bprime_advec, double* xyz_list, double* gauss_coord){
    5261 
    5262 
    5263         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
    5264          * For grid i, Bi' can be expressed in the actual coordinate system
    5265          * by:
    5266          *       Biprime_advec=[ dh/dx ]
    5267          *                       [ dh/dy ]
    5268          *                       [ dh/dz ]
    5269          * where h is the interpolation function for grid i.
    5270          *
    5271          * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
    5272          */
    5273 
    5274         int i;
    5275         const int calculationdof=3;
    5276         const int numgrids=6;
    5277         int DOFPERGRID=1;
    5278 
    5279         /*Same thing in the actual coordinate system: */
    5280         double dh1dh6[calculationdof][numgrids];
    5281 
    5282         /*Get dh1dh2dh3 in actual coordinates system : */
    5283         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list,gauss_coord);
    5284 
    5285         /*Build B': */
    5286         for (i=0;i<numgrids;i++){
    5287                 *(Bprime_advec+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
    5288                 *(Bprime_advec+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
    5289                 *(Bprime_advec+DOFPERGRID*numgrids*2+DOFPERGRID*i)=dh1dh6[2][i];
    5290         }
    5291 }
    5292 /*}}}*/
    5293 /*FUNCTION Penta::GetBPrime_vert {{{1*/
    5294 void Penta::GetBPrime_vert(double* B, double* xyz_list, double* gauss_coord){
    5295 
    5296         // Compute Bprime  matrix. Bprime=[L1 L2 L3 L4 L5 L6] where Li is the nodal function for grid i
    5297 
    5298         int i;
    5299 
    5300         GetNodalFunctions(B, gauss_coord);
    5301 
    5302 }
    5303 /*}}}*/
    5304 /*FUNCTION Penta::GetBprimeStokes {{{1*/
    5305 void Penta::GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss_coord){
    5306 
    5307         /*      Compute B'  matrix. B'=[B1' B2' B3' B4' B5' B6' Bb'] where Bi' is of size 3*NDOF2.
    5308          *      For grid i, Bi' can be expressed in the actual coordinate system
    5309          *      by:
    5310          *                              Bi'=[ dh/dx   0          0       0]
    5311          *                                       [   0      dh/dy      0       0]
    5312          *                                       [   0      0         dh/dz    0]
    5313          *                                       [  dh/dy   dh/dx      0       0]
    5314          *                                       [  dh/dz   0        dh/dx     0]
    5315          *                                       [   0      dh/dz    dh/dy     0]
    5316          *                                       [  dh/dx   dh/dy    dh/dz     0]
    5317          *                                       [   0      0          0       h]
    5318          *      where h is the interpolation function for grid i.
    5319          *
    5320          *      Same thing for the bubble fonction except that there is no fourth column
    5321          */
    5322 
    5323         int i;
    5324         const int calculationdof=3;
    5325         const int numgrids=6;
    5326         int DOFPERGRID=4;
    5327 
    5328         double dh1dh7[calculationdof][numgrids+1];
    5329         double l1l6[numgrids];
    5330 
    5331         /*Get dh1dh7 in actual coordinate system: */
    5332         GetNodalFunctionsDerivativesStokes(&dh1dh7[0][0],xyz_list, gauss_coord);
    5333 
    5334         GetNodalFunctions(l1l6, gauss_coord);
    5335 
    5336         /*B_primeuild B_prime: */
    5337         for (i=0;i<numgrids+1;i++){
    5338                 *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7[0][i]; //B_prime[0][DOFPERGRID*i]=dh1dh6[0][i];
    5339                 *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
    5340                 *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
    5341                 *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
    5342                 *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7[1][i];
    5343                 *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
    5344                 *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
    5345                 *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
    5346                 *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7[2][i];
    5347                 *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=dh1dh7[1][i];
    5348                 *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=dh1dh7[0][i];
    5349                 *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
    5350                 *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=dh1dh7[2][i];
    5351                 *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
    5352                 *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=dh1dh7[0][i];
    5353                 *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
    5354                 *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=dh1dh7[2][i];
    5355                 *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=dh1dh7[1][i];
    5356                 *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=dh1dh7[0][i];
    5357                 *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=dh1dh7[1][i];
    5358                 *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=dh1dh7[2][i];
    5359                 *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=0;
    5360                 *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=0;
    5361                 *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=0;
    5362         }
    5363 
    5364         for (i=0;i<numgrids;i++){ //last column not for the bubble function
    5365                 *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
    5366                 *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
    5367                 *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
    5368                 *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
    5369                 *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
    5370                 *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
    5371                 *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=0;
    5372                 *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=l1l6[i];
    5373         }
    5374 
    5375 }
    5376 /*}}}*/
    5377 /*FUNCTION Penta::GetBStokes {{{1*/
    5378 void Penta::GetBStokes(double* B, double* xyz_list, double* gauss_coord){
    5379 
    5380         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 3*DOFPERGRID.
    5381          * For grid i, Bi can be expressed in the actual coordinate system
    5382          * by:                          Bi=[ dh/dx          0             0       0  ]
    5383          *                                      [   0           dh/dy           0       0  ]
    5384          *                                      [   0             0           dh/dy     0  ]
    5385          *                                      [ 1/2*dh/dy    1/2*dh/dx        0       0  ]
    5386          *                                      [ 1/2*dh/dz       0         1/2*dh/dx   0  ]
    5387          *                                      [   0          1/2*dh/dz    1/2*dh/dy   0  ]
    5388          *                                      [   0             0             0       h  ]
    5389          *                                      [ dh/dx         dh/dy         dh/dz     0  ]
    5390          *      where h is the interpolation function for grid i.
    5391          *      Same thing for Bb except the last column that does not exist.
    5392          */
    5393 
    5394         int i;
    5395         const int calculationdof=3;
    5396         const int numgrids=6;
    5397         int DOFPERGRID=4;
    5398 
    5399         double dh1dh7[calculationdof][numgrids+1];
    5400         double l1l6[numgrids];
    5401 
    5402 
    5403         /*Get dh1dh7 in actual coordinate system: */
    5404         GetNodalFunctionsDerivativesStokes(&dh1dh7[0][0],xyz_list, gauss_coord);
    5405 
    5406         GetNodalFunctions(l1l6, gauss_coord);
    5407 
    5408         /*Build B: */
    5409         for (i=0;i<numgrids+1;i++){
    5410                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7[0][i]; //B[0][DOFPERGRID*i]=dh1dh6[0][i];
    5411                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
    5412                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
    5413                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
    5414                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7[1][i];
    5415                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
    5416                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
    5417                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
    5418                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7[2][i];
    5419                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=(float).5*dh1dh7[1][i];
    5420                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=(float).5*dh1dh7[0][i];
    5421                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
    5422                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=(float).5*dh1dh7[2][i];
    5423                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
    5424                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=(float).5*dh1dh7[0][i];
    5425                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
    5426                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=(float).5*dh1dh7[2][i];
    5427                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=(float).5*dh1dh7[1][i];
    5428                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=0;
    5429                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=0;
    5430                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=0;
    5431                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=dh1dh7[0][i];
    5432                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=dh1dh7[1][i];
    5433                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=dh1dh7[2][i];
    5434         }
    5435 
    5436         for (i=0;i<numgrids;i++){ //last column not for the bubble function
    5437                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
    5438                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
    5439                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
    5440                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
    5441                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
    5442                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
    5443                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=l1l6[i];
    5444                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=0;
    5445         }
    5446 
    5447 }
    5448 /*}}}*/
    5449 /*FUNCTION Penta::GetDofList {{{1*/
    5450 void  Penta::GetDofList(int* doflist,int* pnumberofdofspernode){
    5451 
    5452         int i,j;
    5453         int doflist_per_node[MAXDOFSPERNODE];
    5454         int numberofdofspernode;
    5455 
    5456         for(i=0;i<6;i++){
    5457                 nodes[i]->GetDofList(&doflist_per_node[0],&numberofdofspernode);
    5458                 for(j=0;j<numberofdofspernode;j++){
    5459                         doflist[i*numberofdofspernode+j]=doflist_per_node[j];
    5460                 }
    5461         }
    5462 
    5463         /*Assign output pointers:*/
    5464         *pnumberofdofspernode=numberofdofspernode;
    5465 
    5466 }
    5467 /*}}}*/
    5468 /*FUNCTION Penta::GetDofList1 {{{1*/
    5469 void  Penta::GetDofList1(int* doflist){
    5470        
    5471         int i;
    5472 
    5473         for(i=0;i<6;i++){
    5474                 doflist[i]=nodes[i]->GetDofList1();
    5475         }
    5476 
    5477 }
    5478 /*}}}*/
    5479 /*FUNCTION Penta::GetJacobian {{{1*/
    5480 void Penta::GetJacobian(double* J, double* xyz_list,double* gauss_coord){
    5481 
    5482         const int NDOF3=3;
    5483         int i,j;
    5484 
    5485         /*The Jacobian is constant over the element, discard the gaussian points.
    5486          * J is assumed to have been allocated of size NDOF2xNDOF2.*/
    5487 
    5488         double A1,A2,A3; //area coordinates
    5489         double xi,eta,zi; //parametric coordinates
    5490 
    5491         double x1,x2,x3,x4,x5,x6;
    5492         double y1,y2,y3,y4,y5,y6;
    5493         double z1,z2,z3,z4,z5,z6;
    5494 
    5495         /*Figure out xi,eta and zi (parametric coordinates), for this gaussian point: */
    5496         A1=gauss_coord[0];
    5497         A2=gauss_coord[1];
    5498         A3=gauss_coord[2];
    5499 
    5500         xi=A2-A1;
    5501         eta=SQRT3*A3;
    5502         zi=gauss_coord[3];
    5503 
    5504         x1=*(xyz_list+3*0+0);
    5505         x2=*(xyz_list+3*1+0);
    5506         x3=*(xyz_list+3*2+0);
    5507         x4=*(xyz_list+3*3+0);
    5508         x5=*(xyz_list+3*4+0);
    5509         x6=*(xyz_list+3*5+0);
    5510 
    5511         y1=*(xyz_list+3*0+1);
    5512         y2=*(xyz_list+3*1+1);
    5513         y3=*(xyz_list+3*2+1);
    5514         y4=*(xyz_list+3*3+1);
    5515         y5=*(xyz_list+3*4+1);
    5516         y6=*(xyz_list+3*5+1);
    5517 
    5518         z1=*(xyz_list+3*0+2);
    5519         z2=*(xyz_list+3*1+2);
    5520         z3=*(xyz_list+3*2+2);
    5521         z4=*(xyz_list+3*3+2);
    5522         z5=*(xyz_list+3*4+2);
    5523         z6=*(xyz_list+3*5+2);
    5524 
    5525 
    5526         *(J+NDOF3*0+0)=0.25*(x1-x2-x4+x5)*zi+0.25*(-x1+x2-x4+x5);
    5527         *(J+NDOF3*1+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*zi+SQRT3/12.0*(-x1-x2+2*x3-x4-x5+2*x6);
    5528         *(J+NDOF3*2+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*eta+1/4*(x1-x2-x4+x5)*xi +0.25*(-x1+x5-x2+x4);
    5529 
    5530         *(J+NDOF3*0+1)=0.25*(y1-y2-y4+y5)*zi+0.25*(-y1+y2-y4+y5);
    5531         *(J+NDOF3*1+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*zi+SQRT3/12.0*(-y1-y2+2*y3-y4-y5+2*y6);
    5532         *(J+NDOF3*2+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*eta+0.25*(y1-y2-y4+y5)*xi+0.25*(y4-y1+y5-y2);
    5533 
    5534         *(J+NDOF3*0+2)=0.25*(z1-z2-z4+z5)*zi+0.25*(-z1+z2-z4+z5);
    5535         *(J+NDOF3*1+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*zi+SQRT3/12.0*(-z1-z2+2*z3-z4-z5+2*z6);
    5536         *(J+NDOF3*2+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*eta+0.25*(z1-z2-z4+z5)*xi+0.25*(-z1+z5-z2+z4);
    5537 
    5538 }
    5539 /*}}}*/
    5540 /*FUNCTION Penta::GetJacobianDeterminant {{{1*/
    5541 void Penta::GetJacobianDeterminant(double*  Jdet, double* xyz_list,double* gauss_coord){
    5542 
    5543         /*On a penta, Jacobian varies according to coordinates. We need to get the Jacobian, and take
    5544          * the determinant of it: */
    5545         const int NDOF3=3;
    5546 
    5547         double J[NDOF3][NDOF3];
    5548 
    5549         GetJacobian(&J[0][0],xyz_list,gauss_coord);
    5550 
    5551         *Jdet= J[0][0]*J[1][1]*J[2][2]-J[0][0]*J[1][2]*J[2][1]-J[1][0]*J[0][1]*J[2][2]+J[1][0]*J[0][2]*J[2][1]+J[2][0]*J[0][1]*J[1][2]-J[2][0]*J[0][2]*J[1][1];
    5552 
    5553         if(*Jdet<0){
    5554                 ISSMERROR("%s%i","negative jacobian determinant on element ",id);
    5555         }
    5556 }
    5557 /*}}}*/
    5558 /*FUNCTION Penta::GetJacobianInvert {{{1*/
    5559 void Penta::GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss_coord){
    5560 
    5561         double Jdet;
    5562         const int NDOF3=3;
    5563 
    5564         /*Call Jacobian routine to get the jacobian:*/
    5565         GetJacobian(Jinv, xyz_list, gauss_coord);
    5566 
    5567         /*Invert Jacobian matrix: */
    5568         MatrixInverse(Jinv,NDOF3,NDOF3,NULL,0,&Jdet);
    5569 }
    5570 /*}}}*/
    5571 /*FUNCTION Penta::GetLStokes {{{1*/
    5572 void Penta::GetLStokes(double* LStokes, double* gauss_coord_tria){
    5573 
    5574         /*
    5575          * Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof.
    5576          * For grid i, Li can be expressed in the actual coordinate system
    5577          * by:
    5578          *       Li=[ h    0    0   0]
    5579          *               [ 0    h    0   0]
    5580          *               [ 0    0    h   0]
    5581          *               [ 0    0    h   0]
    5582          *               [ h    0    0   0]
    5583          *               [ 0    h    0   0]
    5584          *               [ h    0    0   0]
    5585          *               [ 0    h    0   0]
    5586          *               [ 0    0    h   0]
    5587          *               [ 0    0    h   0]
    5588          *               [ 0    0    h   0]
    5589          *               [ h    0    0   0]
    5590          *               [ 0    h    0   0]
    5591          *               [ 0    0    h   0]
    5592          * where h is the interpolation function for grid i.
    5593          */
    5594 
    5595         int i;
    5596         const int numgrids2d=3;
    5597         int num_dof=4;
    5598 
    5599         double l1l2l3[numgrids2d];
    5600 
    5601 
    5602         /*Get l1l2l3 in actual coordinate system: */
    5603         l1l2l3[0]=gauss_coord_tria[0];
    5604         l1l2l3[1]=gauss_coord_tria[1];
    5605         l1l2l3[2]=gauss_coord_tria[2];
    5606 
    5607         /*Build LStokes: */
    5608         for (i=0;i<3;i++){
    5609                 *(LStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LStokes[0][NDOF2*i]=dh1dh3[0][i];
    5610                 *(LStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
    5611                 *(LStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
    5612                 *(LStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
    5613                 *(LStokes+num_dof*numgrids2d*1+num_dof*i)=0;
    5614                 *(LStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
    5615                 *(LStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
    5616                 *(LStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
    5617                 *(LStokes+num_dof*numgrids2d*2+num_dof*i)=0;
    5618                 *(LStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
    5619                 *(LStokes+num_dof*numgrids2d*2+num_dof*i+2)=l1l2l3[i];
    5620                 *(LStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
    5621                 *(LStokes+num_dof*numgrids2d*3+num_dof*i)=0;
    5622                 *(LStokes+num_dof*numgrids2d*3+num_dof*i+1)=0;
    5623                 *(LStokes+num_dof*numgrids2d*3+num_dof*i+2)=l1l2l3[i];
    5624                 *(LStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
    5625                 *(LStokes+num_dof*numgrids2d*4+num_dof*i)=l1l2l3[i];
    5626                 *(LStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
    5627                 *(LStokes+num_dof*numgrids2d*4+num_dof*i+2)=0;
    5628                 *(LStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
    5629                 *(LStokes+num_dof*numgrids2d*5+num_dof*i)=0;
    5630                 *(LStokes+num_dof*numgrids2d*5+num_dof*i+1)=l1l2l3[i];
    5631                 *(LStokes+num_dof*numgrids2d*5+num_dof*i+2)=0;
    5632                 *(LStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
    5633                 *(LStokes+num_dof*numgrids2d*6+num_dof*i)=l1l2l3[i];
    5634                 *(LStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
    5635                 *(LStokes+num_dof*numgrids2d*6+num_dof*i+2)=0;
    5636                 *(LStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
    5637                 *(LStokes+num_dof*numgrids2d*7+num_dof*i)=0;
    5638                 *(LStokes+num_dof*numgrids2d*7+num_dof*i+1)=l1l2l3[i];
    5639                 *(LStokes+num_dof*numgrids2d*7+num_dof*i+2)=0;
    5640                 *(LStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
    5641                 *(LStokes+num_dof*numgrids2d*8+num_dof*i)=0;
    5642                 *(LStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
    5643                 *(LStokes+num_dof*numgrids2d*8+num_dof*i+2)=l1l2l3[i];
    5644                 *(LStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
    5645                 *(LStokes+num_dof*numgrids2d*9+num_dof*i)=0;
    5646                 *(LStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
    5647                 *(LStokes+num_dof*numgrids2d*9+num_dof*i+2)=l1l2l3[i];
    5648                 *(LStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
    5649                 *(LStokes+num_dof*numgrids2d*10+num_dof*i)=0;
    5650                 *(LStokes+num_dof*numgrids2d*10+num_dof*i+1)=0;
    5651                 *(LStokes+num_dof*numgrids2d*10+num_dof*i+2)=l1l2l3[i];
    5652                 *(LStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
    5653                 *(LStokes+num_dof*numgrids2d*11+num_dof*i)=l1l2l3[i];
    5654                 *(LStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
    5655                 *(LStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
    5656                 *(LStokes+num_dof*numgrids2d*11+num_dof*i+3)=0;
    5657                 *(LStokes+num_dof*numgrids2d*12+num_dof*i)=0;
    5658                 *(LStokes+num_dof*numgrids2d*12+num_dof*i+1)=l1l2l3[i];
    5659                 *(LStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
    5660                 *(LStokes+num_dof*numgrids2d*12+num_dof*i+3)=0;
    5661                 *(LStokes+num_dof*numgrids2d*13+num_dof*i)=0;
    5662                 *(LStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
    5663                 *(LStokes+num_dof*numgrids2d*13+num_dof*i+2)=l1l2l3[i];
    5664                 *(LStokes+num_dof*numgrids2d*13+num_dof*i+3)=0;
    5665 
    5666         }
    5667 }
    5668 /*}}}*/
    5669 /*FUNCTION Penta::GetLprimeStokes {{{1*/
    5670 void Penta::GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_coord_tria, double* gauss_coord){
    5671 
    5672         /*
    5673          * Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof.
    5674          * For grid i, Lpi can be expressed in the actual coordinate system
    5675          * by:
    5676          *       Lpi=[ h    0    0   0]
    5677          *               [ 0    h    0   0]
    5678          *               [ h    0    0   0]
    5679          *               [ 0    h    0   0]
    5680          *               [ 0    0    h   0]
    5681          *               [ 0    0    h   0]
    5682          *               [ 0    0  dh/dz 0]
    5683          *               [ 0    0  dh/dz 0]
    5684          *               [ 0    0  dh/dz 0]
    5685          *               [dh/dz 0  dh/dx 0]
    5686          *               [ 0 dh/dz dh/dy 0]
    5687          *               [ 0    0    0   h]
    5688          *               [ 0    0    0   h]
    5689          *               [ 0    0    0   h]
    5690          * where h is the interpolation function for grid i.
    5691          */
    5692 
    5693         int i;
    5694         const int numgrids2d=3;
    5695         int num_dof=4;
    5696 
    5697         double l1l2l3[numgrids2d];
    5698         double dh1dh6[3][6];
    5699 
    5700 
    5701         /*Get l1l2l3 in actual coordinate system: */
    5702         l1l2l3[0]=gauss_coord_tria[0];
    5703         l1l2l3[1]=gauss_coord_tria[1];
    5704         l1l2l3[2]=gauss_coord_tria[2];
    5705 
    5706         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list,gauss_coord);
    5707 
    5708         /*Build LprimeStokes: */
    5709         for (i=0;i<3;i++){
    5710                 *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh3[0][i];
    5711                 *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
    5712                 *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
    5713                 *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
    5714                 *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i)=0;
    5715                 *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
    5716                 *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
    5717                 *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
    5718                 *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i)=l1l2l3[i];
    5719                 *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
    5720                 *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+2)=0;
    5721                 *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
    5722                 *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i)=0;
    5723                 *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+1)=l1l2l3[i];
    5724                 *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+2)=0;
    5725                 *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
    5726                 *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i)=0;
    5727                 *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
    5728                 *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+2)=l1l2l3[i];
    5729                 *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
    5730                 *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i)=0;
    5731                 *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+1)=0;
    5732                 *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+2)=l1l2l3[i];
    5733                 *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
    5734                 *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i)=0;
    5735                 *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
    5736                 *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+2)=dh1dh6[2][i];
    5737                 *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
    5738                 *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i)=0;
    5739                 *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+1)=0;
    5740                 *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+2)=dh1dh6[2][i];
    5741                 *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
    5742                 *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i)=0;
    5743                 *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
    5744                 *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+2)=dh1dh6[2][i];
    5745                 *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
    5746                 *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i)=dh1dh6[2][i];
    5747                 *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
    5748                 *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+2)=dh1dh6[0][i];
    5749                 *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
    5750                 *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i)=0;
    5751                 *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+1)=dh1dh6[2][i];
    5752                 *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+2)=dh1dh6[1][i];
    5753                 *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
    5754                 *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i)=0;
    5755                 *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
    5756                 *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
    5757                 *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+3)=l1l2l3[i];
    5758                 *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i)=0;
    5759                 *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+1)=0;
    5760                 *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
    5761                 *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+3)=l1l2l3[i];
    5762                 *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i)=0;
    5763                 *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
    5764                 *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+2)=0;
    5765                 *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+3)=l1l2l3[i];
    5766 
    5767         }
    5768 }
    5769 /*}}}*/
    5770 /*FUNCTION Penta::GetMatrixInvert {{{1*/
    5771 void Penta::GetMatrixInvert(double*  Ke_invert, double* Ke){
    5772         /*Inverse a 3 by 3 matrix only */
    5773 
    5774         double a,b,c,d,e,f,g,h,i;
    5775         double det;
    5776         int calculationdof=3;
    5777 
    5778         /*Take the matrix components: */
    5779         a=*(Ke+calculationdof*0+0);
    5780         b=*(Ke+calculationdof*0+1);
    5781         c=*(Ke+calculationdof*0+2);
    5782         d=*(Ke+calculationdof*1+0);
    5783         e=*(Ke+calculationdof*1+1);
    5784         f=*(Ke+calculationdof*1+2);
    5785         g=*(Ke+calculationdof*2+0);
    5786         h=*(Ke+calculationdof*2+1);
    5787         i=*(Ke+calculationdof*2+2);
    5788 
    5789         det=a*(e*i-f*h)-b*(d*i-f*g)+c*(d*h-e*g);
    5790 
    5791         *(Ke_invert+calculationdof*0+0)=(e*i-f*h)/det;
    5792         *(Ke_invert+calculationdof*0+1)=(c*h-b*i)/det;
    5793         *(Ke_invert+calculationdof*0+2)=(b*f-c*e)/det;
    5794         *(Ke_invert+calculationdof*1+0)=(f*g-d*i)/det;
    5795         *(Ke_invert+calculationdof*1+1)=(a*i-c*g)/det;
    5796         *(Ke_invert+calculationdof*1+2)=(c*d-a*f)/det;
    5797         *(Ke_invert+calculationdof*2+0)=(d*h-e*g)/det;
    5798         *(Ke_invert+calculationdof*2+1)=(b*g-a*h)/det;
    5799         *(Ke_invert+calculationdof*2+2)=(a*e-b*d)/det;
    5800 
    5801 }
    5802 /*}}}*/
    5803 /*FUNCTION Penta::GetNodalFunctions {{{1*/
    5804 void Penta::GetNodalFunctions(double* l1l6, double* gauss_coord){
    5805 
    5806         /*This routine returns the values of the nodal functions  at the gaussian point.*/
    5807 
    5808         l1l6[0]=gauss_coord[0]*(1-gauss_coord[3])/2.0;
    5809 
    5810         l1l6[1]=gauss_coord[1]*(1-gauss_coord[3])/2.0;
    5811 
    5812         l1l6[2]=gauss_coord[2]*(1-gauss_coord[3])/2.0;
    5813 
    5814         l1l6[3]=gauss_coord[0]*(1+gauss_coord[3])/2.0;
    5815 
    5816         l1l6[4]=gauss_coord[1]*(1+gauss_coord[3])/2.0;
    5817 
    5818         l1l6[5]=gauss_coord[2]*(1+gauss_coord[3])/2.0;
    5819 
    5820 }
    5821 /*}}}*/
    5822 /*FUNCTION Penta::GetNodalFunctionsDerivatives {{{1*/
    5823 void Penta::GetNodalFunctionsDerivatives(double* dh1dh6,double* xyz_list, double* gauss_coord){
    5824 
    5825         /*This routine returns the values of the nodal functions derivatives  (with respect to the actual coordinate system: */
    5826 
    5827 
    5828         int i;
    5829         const int NDOF3=3;
    5830         const int numgrids=6;
    5831 
    5832         double dh1dh6_ref[NDOF3][numgrids];
    5833         double Jinv[NDOF3][NDOF3];
    5834 
    5835         /*Get derivative values with respect to parametric coordinate system: */
    5836         GetNodalFunctionsDerivativesReference(&dh1dh6_ref[0][0], gauss_coord);
    5837 
    5838         /*Get Jacobian invert: */
    5839         GetJacobianInvert(&Jinv[0][0], xyz_list, gauss_coord);
    5840 
    5841         /*Build dh1dh3:
    5842          *
    5843          * [dhi/dx]= Jinv*[dhi/dr]
    5844          * [dhi/dy]       [dhi/ds]
    5845          * [dhi/dz]       [dhi/dn]
    5846          */
    5847 
    5848         for (i=0;i<numgrids;i++){
    5849                 *(dh1dh6+numgrids*0+i)=Jinv[0][0]*dh1dh6_ref[0][i]+Jinv[0][1]*dh1dh6_ref[1][i]+Jinv[0][2]*dh1dh6_ref[2][i];
    5850                 *(dh1dh6+numgrids*1+i)=Jinv[1][0]*dh1dh6_ref[0][i]+Jinv[1][1]*dh1dh6_ref[1][i]+Jinv[1][2]*dh1dh6_ref[2][i];
    5851                 *(dh1dh6+numgrids*2+i)=Jinv[2][0]*dh1dh6_ref[0][i]+Jinv[2][1]*dh1dh6_ref[1][i]+Jinv[2][2]*dh1dh6_ref[2][i];
    5852         }
    5853 
    5854 }
    5855 /*}}}*/
    5856 /*FUNCTION Penta::GetNodalFunctionsDerivativesStokes {{{1*/
    5857 void Penta::GetNodalFunctionsDerivativesStokes(double* dh1dh7,double* xyz_list, double* gauss_coord){
    5858 
    5859         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    5860          * actual coordinate system: */
    5861 
    5862         int i;
    5863 
    5864         const  int numgrids=7;
    5865         double dh1dh7_ref[3][numgrids];
    5866         double Jinv[3][3];
    5867 
    5868 
    5869         /*Get derivative values with respect to parametric coordinate system: */
    5870         GetNodalFunctionsDerivativesReferenceStokes(&dh1dh7_ref[0][0], gauss_coord);
    5871 
    5872         /*Get Jacobian invert: */
    5873         GetJacobianInvert(&Jinv[0][0], xyz_list, gauss_coord);
    5874 
    5875         /*Build dh1dh6:
    5876          *
    5877          * [dhi/dx]= Jinv'*[dhi/dr]
    5878          * [dhi/dy]        [dhi/ds]
    5879          * [dhi/dz]        [dhi/dzeta]
    5880          */
    5881 
    5882         for (i=0;i<numgrids;i++){
    5883                 *(dh1dh7+numgrids*0+i)=Jinv[0][0]*dh1dh7_ref[0][i]+Jinv[0][1]*dh1dh7_ref[1][i]+Jinv[0][2]*dh1dh7_ref[2][i];
    5884                 *(dh1dh7+numgrids*1+i)=Jinv[1][0]*dh1dh7_ref[0][i]+Jinv[1][1]*dh1dh7_ref[1][i]+Jinv[1][2]*dh1dh7_ref[2][i];
    5885                 *(dh1dh7+numgrids*2+i)=Jinv[2][0]*dh1dh7_ref[0][i]+Jinv[2][1]*dh1dh7_ref[1][i]+Jinv[2][2]*dh1dh7_ref[2][i];
    5886         }
    5887 
    5888 }
    5889 /*}}}*/
    5890 /*FUNCTION Penta::GetNodalFunctionsDerivativesReference {{{1*/
    5891 void Penta::GetNodalFunctionsDerivativesReference(double* dl1dl6,double* gauss_coord){
    5892 
    5893         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    5894          * natural coordinate system) at the gaussian point. Those values vary along xi,eta,z */
    5895 
    5896         const int numgrids=6;
    5897         double A1,A2,A3,z;
    5898 
    5899         A1=gauss_coord[0]; //first area coordinate value. In term of xi and eta: A1=(1-xi)/2-eta/(2*SQRT3);
    5900         A2=gauss_coord[1]; //second area coordinate value In term of xi and eta: A2=(1+xi)/2-eta/(2*SQRT3);
    5901         A3=gauss_coord[2]; //third area coordinate value  In term of xi and eta: A3=y/SQRT3;
    5902         z=gauss_coord[3]; //fourth vertical coordinate value. Corresponding nodal function: (1-z)/2 and (1+z)/2
    5903 
    5904 
    5905         /*First nodal function derivatives. The corresponding nodal function is N=A1*(1-z)/2. Its derivatives follow*/
    5906         *(dl1dl6+numgrids*0+0)=-0.5*(1.0-z)/2.0;
    5907         *(dl1dl6+numgrids*1+0)=-0.5/SQRT3*(1.0-z)/2.0;
    5908         *(dl1dl6+numgrids*2+0)=-0.5*A1;
    5909 
    5910         /*Second nodal function: The corresponding nodal function is N=A2*(1-z)/2. Its derivatives follow*/
    5911         *(dl1dl6+numgrids*0+1)=0.5*(1.0-z)/2.0;
    5912         *(dl1dl6+numgrids*1+1)=-0.5/SQRT3*(1.0-z)/2.0;
    5913         *(dl1dl6+numgrids*2+1)=-0.5*A2;
    5914 
    5915         /*Third nodal function: The corresponding nodal function is N=A3*(1-z)/2. Its derivatives follow*/
    5916         *(dl1dl6+numgrids*0+2)=0.0;
    5917         *(dl1dl6+numgrids*1+2)=1.0/SQRT3*(1.0-z)/2.0;
    5918         *(dl1dl6+numgrids*2+2)=-0.5*A3;
    5919 
    5920         /*Fourth nodal function: The corresponding nodal function is N=A1*(1+z)/2. Its derivatives follow*/
    5921         *(dl1dl6+numgrids*0+3)=-0.5*(1.0+z)/2.0;
    5922         *(dl1dl6+numgrids*1+3)=-0.5/SQRT3*(1.0+z)/2.0;
    5923         *(dl1dl6+numgrids*2+3)=0.5*A1;
    5924 
    5925         /*Fifth nodal function: The corresponding nodal function is N=A2*(1+z)/2. Its derivatives follow*/
    5926         *(dl1dl6+numgrids*0+4)=0.5*(1.0+z)/2.0;
    5927         *(dl1dl6+numgrids*1+4)=-0.5/SQRT3*(1.0+z)/2.0;
    5928         *(dl1dl6+numgrids*2+4)=0.5*A2;
    5929 
    5930         /*Sixth nodal function: The corresponding nodal function is N=A3*(1+z)/2. Its derivatives follow*/
    5931         *(dl1dl6+numgrids*0+5)=0.0;
    5932         *(dl1dl6+numgrids*1+5)=1.0/SQRT3*(1.0+z)/2.0;
    5933         *(dl1dl6+numgrids*2+5)=0.5*A3;
    5934 }
    5935 /*}}}*/
    5936 /*FUNCTION Penta::GetNodalFunctionsDerivativesReferenceStokes {{{1*/
    5937 void Penta::GetNodalFunctionsDerivativesReferenceStokes(double* dl1dl7,double* gauss_coord){
    5938 
    5939         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    5940          * natural coordinate system) at the gaussian point. */
    5941 
    5942         int    numgrids=7; //six plus bubble grids
    5943 
    5944         double r=gauss_coord[1]-gauss_coord[0];
    5945         double s=-3.0/SQRT3*(gauss_coord[0]+gauss_coord[1]-2.0/3.0);
    5946         double zeta=gauss_coord[3];
    5947 
    5948         /*First nodal function: */
    5949         *(dl1dl7+numgrids*0+0)=-0.5*(1.0-zeta)/2.0;
    5950         *(dl1dl7+numgrids*1+0)=-SQRT3/6.0*(1.0-zeta)/2.0;
    5951         *(dl1dl7+numgrids*2+0)=-0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
    5952 
    5953         /*Second nodal function: */
    5954         *(dl1dl7+numgrids*0+1)=0.5*(1.0-zeta)/2.0;
    5955         *(dl1dl7+numgrids*1+1)=-SQRT3/6.0*(1.0-zeta)/2.0;
    5956         *(dl1dl7+numgrids*2+1)=-0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
    5957 
    5958         /*Third nodal function: */
    5959         *(dl1dl7+numgrids*0+2)=0;
    5960         *(dl1dl7+numgrids*1+2)=SQRT3/3.0*(1.0-zeta)/2.0;
    5961         *(dl1dl7+numgrids*2+2)=-0.5*(SQRT3/3.0*s+ONETHIRD);
    5962 
    5963         /*Fourth nodal function: */
    5964         *(dl1dl7+numgrids*0+3)=-0.5*(1.0+zeta)/2.0;
    5965         *(dl1dl7+numgrids*1+3)=-SQRT3/6.0*(1.0+zeta)/2.0;
    5966         *(dl1dl7+numgrids*2+3)=0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
    5967 
    5968         /*Fith nodal function: */
    5969         *(dl1dl7+numgrids*0+4)=0.5*(1.0+zeta)/2.0;
    5970         *(dl1dl7+numgrids*1+4)=-SQRT3/6.0*(1.0+zeta)/2.0;
    5971         *(dl1dl7+numgrids*2+4)=0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
    5972 
    5973         /*Sixth nodal function: */
    5974         *(dl1dl7+numgrids*0+5)=0;
    5975         *(dl1dl7+numgrids*1+5)=SQRT3/3.0*(1.0+zeta)/2.0;
    5976         *(dl1dl7+numgrids*2+5)=0.5*(SQRT3/3.0*s+ONETHIRD);
    5977 
    5978         /*Seventh nodal function: */
    5979         *(dl1dl7+numgrids*0+6)=9.0/2.0*r*(1.0+zeta)*(zeta-1.0)*(SQRT3*s+1.0);
    5980         *(dl1dl7+numgrids*1+6)=9.0/4.0*(1+zeta)*(1-zeta)*(SQRT3*pow(s,2.0)-2.0*s-SQRT3*pow(r,2.0));
    5981         *(dl1dl7+numgrids*2+6)=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(-2.0*zeta);
    5982 
    5983 }
    5984 /*}}}*/
    5985 /*FUNCTION Penta::GetNodalFunctionsStokes {{{1*/
    5986 void Penta::GetNodalFunctionsStokes(double* l1l7, double* gauss_coord){
    5987 
    5988         /*This routine returns the values of the nodal functions  at the gaussian point.*/
    5989 
    5990         /*First nodal function: */
    5991         l1l7[0]=gauss_coord[0]*(1.0-gauss_coord[3])/2.0;
    5992 
    5993         /*Second nodal function: */
    5994         l1l7[1]=gauss_coord[1]*(1.0-gauss_coord[3])/2.0;
    5995 
    5996         /*Third nodal function: */
    5997         l1l7[2]=gauss_coord[2]*(1.0-gauss_coord[3])/2.0;
    5998 
    5999         /*Fourth nodal function: */
    6000         l1l7[3]=gauss_coord[0]*(1.0+gauss_coord[3])/2.0;
    6001 
    6002         /*Fifth nodal function: */
    6003         l1l7[4]=gauss_coord[1]*(1.0+gauss_coord[3])/2.0;
    6004 
    6005         /*Sixth nodal function: */
    6006         l1l7[5]=gauss_coord[2]*(1.0+gauss_coord[3])/2.0;
    6007 
    6008         /*Seventh nodal function: */
    6009         l1l7[6]=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(1.0+gauss_coord[3])*(1.0-gauss_coord[3]);
    6010 
    6011 }
    6012 /*}}}*/
    6013 /*FUNCTION Penta::GetParameterDerivativeValue {{{1*/
    6014 void Penta::GetParameterDerivativeValue(double* p, double* p_list,double* xyz_list, double* gauss_coord){
    6015 
    6016         /*From grid values of parameter p (p_list[0], p_list[1], p_list[2], p_list[3], p_list[4] and p_list[4]), return parameter derivative value at gaussian point specified by gauss_coord:
    6017          *   dp/dx=p_list[0]*dh1/dx+p_list[1]*dh2/dx+p_list[2]*dh3/dx+p_list[3]*dh4/dx+p_list[4]*dh5/dx+p_list[5]*dh6/dx;
    6018          *   dp/dy=p_list[0]*dh1/dy+p_list[1]*dh2/dy+p_list[2]*dh3/dy+p_list[3]*dh4/dy+p_list[4]*dh5/dy+p_list[5]*dh6/dy;
    6019          *   dp/dz=p_list[0]*dh1/dz+p_list[1]*dh2/dz+p_list[2]*dh3/dz+p_list[3]*dh4/dz+p_list[4]*dh5/dz+p_list[5]*dh6/dz;
    6020          *
    6021          *   p is a vector of size 3x1 already allocated.
    6022          */
    6023 
    6024         const int NDOF3=3;
    6025         const int numgrids=6;
    6026         double dh1dh6[NDOF3][numgrids];
    6027 
    6028         /*Get dh1dh6 in actual coordinate system: */
    6029         GetNodalFunctionsDerivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
    6030 
    6031         *(p+0)=p_list[0]*dh1dh6[0][0]+p_list[1]*dh1dh6[0][1]+p_list[2]*dh1dh6[0][2]+p_list[3]*dh1dh6[0][3]+p_list[4]*dh1dh6[0][4]+p_list[5]*dh1dh6[0][5];
    6032         ;
    6033         *(p+1)=p_list[0]*dh1dh6[1][0]+p_list[1]*dh1dh6[1][1]+p_list[2]*dh1dh6[1][2]+p_list[3]*dh1dh6[1][3]+p_list[4]*dh1dh6[1][4]+p_list[5]*dh1dh6[1][5];
    6034 
    6035         *(p+2)=p_list[0]*dh1dh6[2][0]+p_list[1]*dh1dh6[2][1]+p_list[2]*dh1dh6[2][2]+p_list[3]*dh1dh6[2][3]+p_list[4]*dh1dh6[2][4]+p_list[5]*dh1dh6[2][5];
    6036 
    6037 }
    6038 /*}}}*/
    6039 /*FUNCTION Penta::GetParameterValue(double* pvalue, double* v_list,double* gauss_coord) {{{1*/
    6040 void Penta::GetParameterValue(double* pvalue, double* v_list,double* gauss_coord){
    6041 
    6042         const int numgrids=6;
    6043         double l1l6[numgrids];
    6044 
    6045         GetNodalFunctions(&l1l6[0], gauss_coord);
    6046 
    6047         *pvalue=l1l6[0]*v_list[0]+l1l6[1]*v_list[1]+l1l6[2]*v_list[2]+l1l6[3]*v_list[3]+l1l6[4]*v_list[4]+l1l6[5]*v_list[5];
    6048 }
    6049 /*}}}*/
    6050 /*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node1,Node* node2,double gauss_seg,int enumtype) {{{1*/
    6051 void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
    6052 
    6053         /*Output*/
    6054         double value;
    6055 
    6056         /*Intermediaries*/
    6057         const int numnodes=6;
    6058         int       grid=-1;
    6059         int       i;
    6060         double gauss[numnodes][4]={{1,0,0,-1},{0,1,0,-1},{0,0,1,-1},{1,0,0,1},{0,1,0,1},{0,0,1,1}};
    6061 
    6062         /*go through 3 nodes (all nodes for tria) and identify 1st and 2nd nodes: */
    6063         ISSMASSERT(nodes);
    6064         for(i=0;i<numnodes;i++){
    6065                 if (node==nodes[i]){
    6066                         grid=i;
    6067                         break;
    6068                 }
    6069         }
    6070 
    6071         /*Check that the node has been found*/
    6072         if (grid==-1) ISSMERROR("Node pointer not found in Penta's nodes");
    6073 
    6074         /*Get Parameter value on node*/
    6075         inputs->GetParameterValue(pvalue,&gauss[grid][0],enumtype);
    6076         return;
    6077 
    6078 }
    6079 /*}}}*/
    6080 /*FUNCTION Penta::GetPhi {{{1*/
    6081 void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
    6082         /*Compute deformational heating from epsilon and viscosity */
    6083 
    6084         double epsilon_matrix[3][3];
    6085         double epsilon_eff;
    6086         double epsilon_sqr[3][3];
    6087 
    6088         /* Build epsilon matrix */
    6089         epsilon_matrix[0][0]=*(epsilon+0);
    6090         epsilon_matrix[1][0]=*(epsilon+3);
    6091         epsilon_matrix[2][0]=*(epsilon+4);
    6092         epsilon_matrix[0][1]=*(epsilon+3);
    6093         epsilon_matrix[1][1]=*(epsilon+1);
    6094         epsilon_matrix[2][1]=*(epsilon+5);
    6095         epsilon_matrix[0][2]=*(epsilon+4);
    6096         epsilon_matrix[1][2]=*(epsilon+5);
    6097         epsilon_matrix[2][2]=*(epsilon+2);
    6098 
    6099         /* Effective value of epsilon_matrix */
    6100         epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
    6101         epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
    6102         epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
    6103         epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
    6104         epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
    6105         epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
    6106         epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
    6107         epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
    6108         epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
    6109 
    6110         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);
    6111         *phi=2*pow(epsilon_eff,2.0)*viscosity;
    6112 }
    6113 /*}}}*/
    6114 /*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
    6115 void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, double* gauss, Input* vx_input, Input* vy_input){
    6116         /*Compute the 3d Blatter/PattynStrain Rate (5 components):
    6117          *
    6118          * epsilon=[exx eyy exy exz eyz]
    6119          *
    6120          * with exz=1/2 du/dz
    6121          *      eyz=1/2 dv/dz
    6122          *
    6123          * the contribution of vz is neglected
    6124          */
    6125 
    6126         int i;
    6127 
    6128         double epsilonvx[5];
    6129         double epsilonvy[5];
    6130 
    6131         /*Check that both inputs have been found*/
    6132         if (!vx_input || !vy_input){
    6133                 ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
    6134         }
    6135 
    6136         /*Get strain rate assuming that epsilon has been allocated*/
    6137         vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
    6138         vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
    6139 
    6140         /*Sum all contributions*/
    6141         for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
    6142 
    6143 }
    6144 /*}}}*/
    6145 /*FUNCTION Penta::GetStrainRate3d{{{1*/
    6146 void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, double* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
    6147         /*Compute the 3d Strain Rate (6 components):
    6148          *
    6149          * epsilon=[exx eyy ezz exy exz eyz]
    6150          */
    6151 
    6152         int i;
    6153 
    6154         double epsilonvx[6];
    6155         double epsilonvy[6];
    6156         double epsilonvz[6];
    6157 
    6158         /*Check that both inputs have been found*/
    6159         if (!vx_input || !vy_input || !vz_input){
    6160                 ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
    6161         }
    6162 
    6163         /*Get strain rate assuming that epsilon has been allocated*/
    6164         vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
    6165         vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
    6166         vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
    6167 
    6168         /*Sum all contributions*/
    6169         for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
    6170 
    6171 }
    6172 /*}}}*/
    6173 /*FUNCTION Penta::GradjB {{{1*/
    6174 void  Penta::GradjB(Vec gradient){
    6175 
    6176         int i;
    6177         Tria* tria=NULL;
    6178         TriaVertexInput* triavertexinput=NULL;
    6179 
    6180         /*inputs: */
    6181         bool onwater;
    6182         bool collapse;
    6183         bool onbed;
    6184 
    6185         /*retrieve inputs :*/
    6186         inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
    6187         inputs->GetParameterValue(&collapse,CollapseEnum);
    6188         inputs->GetParameterValue(&onbed,ElementOnBedEnum);
    6189 
    6190         /*If on water, skip: */
    6191         if(onwater)return;
    6192 
    6193         if (collapse){
    6194                 /*Bail out element if collapsed (2d) and not on bed*/
    6195                 if (!onbed) return;
    6196 
    6197                 /*This element should be collapsed into a tria element at its base. Create this tria element,
    6198                  * and compute gardj*/
    6199                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    6200                 tria->GradjB(gradient);
    6201                 delete tria;
    6202         }
    6203         else{
    6204                 /*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
    6205                 tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
    6206                 tria->GradjB(gradient);
    6207                 delete tria;
    6208         }
    6209        
    6210 
    6211 }
    6212 /*}}}*/
    62135156/*FUNCTION Penta::ReduceMatrixStokes {{{1*/
    62145157void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
     
    63055248}
    63065249/*}}}1*/
     5250/*FUNCTION Penta::SpawnTria {{{1*/
     5251Tria*  Penta::SpawnTria(int g0, int g1, int g2){
     5252
     5253        int i;
     5254        int analysis_counter;
     5255       
     5256        /*go into parameters and get the analysis_counter: */
     5257        this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
     5258
     5259        /*out of grids g0,g1 and g2 from Penta, build a tria element: */
     5260        Tria* tria=NULL;
     5261        int indices[3];
     5262        int zero=0;
     5263        Parameters* tria_parameters=NULL;
     5264        Inputs* tria_inputs=NULL;
     5265        Results* tria_results=NULL;
     5266
     5267        indices[0]=g0;
     5268        indices[1]=g1;
     5269        indices[2]=g2;
     5270
     5271        tria_parameters=this->parameters;
     5272        tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
     5273        tria_results=(Results*)this->results->SpawnTriaResults(indices);
     5274       
     5275        tria=new Tria();
     5276        tria->id=this->id;
     5277        tria->inputs=tria_inputs;
     5278        tria->results=tria_results;
     5279        tria->parameters=tria_parameters;
     5280        tria->element_type=P1Enum; //Only P1 CG for now
     5281        this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
     5282
     5283        /*recover nodes, matice and matpar: */
     5284        tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
     5285        tria->matice=(Matice*)tria->hmatice->delivers();
     5286        tria->matpar=(Matpar*)tria->hmatpar->delivers();
     5287       
     5288        return tria;
     5289}
     5290/*}}}*/
     5291/*FUNCTION Penta::SpawnBeam {{{1*/
     5292void* Penta::SpawnBeam(int g0, int g1){
     5293
     5294        int i;
     5295
     5296        /*out of grids g0,g1 and g2 from Penta, build a beam element: */
     5297        Beam* beam=NULL;
     5298        int indices[2];
     5299        int zero=0;
     5300        Parameters *beam_parameters = NULL;
     5301        Inputs     *beam_inputs     = NULL;
     5302
     5303        indices[0]=g0;
     5304        indices[1]=g1;
     5305
     5306        beam_parameters=this->parameters;
     5307        beam_inputs=(Inputs*)this->inputs->SpawnBeamInputs(indices);
     5308
     5309        beam=new Beam();
     5310        beam->id=this->id;
     5311        beam->inputs=beam_inputs;
     5312        beam->parameters=beam_parameters;
     5313
     5314        /*now deal with ndoes,matice and matpar: */
     5315        beam->nodes=(Node**)xmalloc(2*sizeof(Node*));
     5316        for(i=0;i<2;i++)beam->nodes[i]=this->nodes[indices[i]];
     5317        beam->matice=this->matice;
     5318        beam->matpar=this->matpar;
     5319
     5320        return beam;
     5321}
     5322/*}}}*/
     5323/*FUNCTION Penta::SpawnSing {{{1*/
     5324void* Penta::SpawnSing(int index){
     5325
     5326        Sing* sing=NULL;
     5327        int zero=0;
     5328        Parameters *sing_parameters = NULL;
     5329        Inputs     *sing_inputs     = NULL;
     5330
     5331        sing_parameters=this->parameters;
     5332        sing_inputs=(Inputs*)this->inputs->SpawnSingInputs(index);
     5333
     5334        sing=new Sing();
     5335        sing->id=this->id;
     5336        sing->inputs=sing_inputs;
     5337        sing->parameters=sing_parameters;
     5338
     5339        /*now deal with nodes,matice and matpar: */
     5340        sing->node=this->nodes[index];
     5341        sing->matice=this->matice;
     5342        sing->matpar=this->matpar;
     5343       
     5344        return sing;
     5345}
     5346/*}}}*/
    63075347/*FUNCTION Penta::SurfaceNormal {{{1*/
    63085348void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
     
    63315371}
    63325372/*}}}*/
     5373/*FUNCTION Penta::VecExtrude {{{1*/
     5374void  Penta::VecExtrude(Vec vector,double* vector_serial,int iscollapsed){
     5375
     5376        /* node data: */
     5377        int   i;
     5378        Node* node=NULL;
     5379        int   extrude=0;
     5380
     5381        /*inputs: */
     5382        bool collapse;
     5383        bool onbed;
     5384
     5385        /*retrieve inputs :*/
     5386        inputs->GetParameterValue(&collapse,CollapseEnum);
     5387        inputs->GetParameterValue(&onbed,ElementOnBedEnum);
     5388
     5389        /*Figure out if we should extrude for this element: */
     5390        if (iscollapsed){
     5391                /*From higher level, we are told to extrude only elements that have the collapse flag on: */
     5392                if (collapse)extrude=1;
     5393                else extrude=0;
     5394        }
     5395        else{
     5396                /*From higher level, we are told to extrude all elements: */
     5397                extrude=1;
     5398        }
     5399
     5400        /*Now, extrusion starts from the bed on, so double check this element is on
     5401         * the bedrock: */
     5402        if(onbed==0)extrude=0;
     5403
     5404        /*Go on and extrude vector: */
     5405        if (extrude){
     5406
     5407                /* node data: */
     5408                int          dof1;
     5409                double       vectorel;
     5410
     5411                /*this penta is a collapsed macayeal. For each node on the base of this penta,
     5412                 * we grab the vector. Once we know the vector, we follow the upper nodes,
     5413                 * inserting the same vector value into vector, until we reach the surface: */
     5414                for(i=0;i<3;i++){
     5415
     5416                        node=nodes[i]; //base nodes
     5417                        dof1=node->GetDofList1();
     5418
     5419                        /*get vector for this base node: */
     5420                        vectorel=vector_serial[dof1];
     5421
     5422                        //go throvectorn all nodes which sit on top of this node, until we reach the surface,
     5423                        //and plvector  vector in vector
     5424                        for(;;){
     5425
     5426                                dof1=node->GetDofList1();
     5427                                VecSetValues(vector,1,&dof1,&vectorel,INSERT_VALUES);
     5428
     5429                                if (node->IsOnSurface())break;
     5430                                /*get next node: */
     5431                                node=node->GetUpperNode();
     5432                        }
     5433                }
     5434        }
     5435}
     5436/*}}}*/
  • issm/trunk/src/c/objects/Elements/Penta.h

    r4882 r4885  
    136136                void      CreatePVectorSlope( Vec pg);
    137137                void      CreatePVectorThermal( Vec pg);
    138                 double*   GaussFromNode(Node* node);
    139                 void      GetB(double* pB, double* xyz_list, double* gauss_coord);
    140                 void      GetBPrime(double* B, double* xyz_list, double* gauss_coord);
    141                 void      GetBPrime_vert(double* B, double* xyz_list, double* gauss_coord);
    142                 void      GetBStokes(double* B, double* xyz_list, double* gauss_coord);
    143                 void      GetB_advec(double* B_advec, double* xyz_list, double* gauss_coord);
    144                 void      GetB_artdiff(double* B_artdiff, double* xyz_list, double* gauss_coord);
    145                 void      GetB_conduct(double* B_conduct, double* xyz_list, double* gauss_coord);
    146                 void      GetB_vert(double* B, double* xyz_list, double* gauss_coord);
    147                 void      GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss_coord);
    148                 void      GetBprime_advec(double* Bprime_advec, double* xyz_list, double* gauss_coord);
     138                double* GaussFromNode(Node* node);
    149139                void      GetDofList(int* doflist,int* pnumberofdofs);
    150140                void      GetDofList1(int* doflist);
    151                 void      GetJacobian(double* J, double* xyz_list,double* gauss_coord);
    152                 void      GetJacobianDeterminant(double*  Jdet, double* xyz_list,double* gauss_coord);
    153                 void      GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss_coord);
    154                 void      GetLStokes(double* LStokes, double* gauss_coord_tria);
    155                 void      GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_coord_tria, double* gauss_coord);
     141                int     GetElementType(void);
    156142                void      GetMatrixInvert(double*  Ke_invert, double* Ke);
    157143                void      GetNodalFunctions(double* l1l6, double* gauss_coord);
     
    161147                void      GetNodalFunctionsDerivativesStokes(double* dh1dh7,double* xyz_list, double* gauss_coord);
    162148                void      GetNodalFunctionsStokes(double* l1l7, double* gauss_coord);
    163                 void      GetParameterDerivativeValue(double* p, double* p_list,double* xyz_list, double* gauss_coord);
    164149                void      GetParameterValue(double* pvalue, double* v_list,double* gauss_coord);
    165150                void    GetParameterValue(double* pvalue,Node* node,int enumtype);
  • issm/trunk/src/c/objects/Elements/PentaRef.cpp

    r4882 r4885  
    5252
    5353/*Reference Element numerics*/
     54/*FUNCTION PentaRef::GetBPattyn {{{1*/
     55void PentaRef::GetBPattyn(double* B, double* xyz_list, double* gauss){
     56        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2.
     57         * For grid i, Bi can be expressed in the actual coordinate system
     58         * by:
     59         *       Bi=[ dh/dx          0      ]
     60         *          [   0           dh/dy   ]
     61         *          [ 1/2*dh/dy  1/2*dh/dx  ]
     62         *          [ 1/2*dh/dz      0      ]
     63         *          [  0         1/2*dh/dz  ]
     64         * where h is the interpolation function for grid i.
     65         *
     66         * We assume B has been allocated already, of size: 5x(NDOF2*numgrids)
     67         */
     68
     69        int i;
     70        const int numgrids=6;
     71        const int NDOF3=3;
     72        const int NDOF2=2;
     73
     74        double dh1dh6[NDOF3][numgrids];
     75
     76        /*Get dh1dh6 in actual coordinate system: */
     77        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss);
     78
     79        /*Build B: */
     80        for (i=0;i<numgrids;i++){
     81                *(B+NDOF2*numgrids*0+NDOF2*i)=dh1dh6[0][i];
     82                *(B+NDOF2*numgrids*0+NDOF2*i+1)=0.0;
     83
     84                *(B+NDOF2*numgrids*1+NDOF2*i)=0.0;
     85                *(B+NDOF2*numgrids*1+NDOF2*i+1)=dh1dh6[1][i];
     86
     87                *(B+NDOF2*numgrids*2+NDOF2*i)=(float).5*dh1dh6[1][i];
     88                *(B+NDOF2*numgrids*2+NDOF2*i+1)=(float).5*dh1dh6[0][i];
     89
     90                *(B+NDOF2*numgrids*3+NDOF2*i)=(float).5*dh1dh6[2][i];
     91                *(B+NDOF2*numgrids*3+NDOF2*i+1)=0.0;
     92
     93                *(B+NDOF2*numgrids*4+NDOF2*i)=0.0;
     94                *(B+NDOF2*numgrids*4+NDOF2*i+1)=(float).5*dh1dh6[2][i];
     95        }
     96
     97}
     98/*}}}*/
     99/*FUNCTION PentaRef::GetBprimePattyn {{{1*/
     100void PentaRef::GetBprimePattyn(double* B, double* xyz_list, double* gauss_coord){
     101        /*Compute B  prime matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2.
     102         * For grid i, Bi can be expressed in the actual coordinate system
     103         * by:
     104         *       Bi=[ 2*dh/dx     dh/dy   ]
     105         *                [   dh/dx    2*dh/dy  ]
     106         *                [ dh/dy      dh/dx    ]
     107         *                [ dh/dz         0     ]
     108         *                [  0         dh/dz    ]
     109         * where h is the interpolation function for grid i.
     110         *
     111         * We assume B has been allocated already, of size: 5x(NDOF2*numgrids)
     112         */
     113
     114        int i;
     115        const int NDOF3=3;
     116        const int NDOF2=2;
     117        const int numgrids=6;
     118
     119        double dh1dh6[NDOF3][numgrids];
     120
     121        /*Get dh1dh6 in actual coordinate system: */
     122        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
     123
     124        /*Build BPrime: */
     125        for (i=0;i<numgrids;i++){
     126                *(B+NDOF2*numgrids*0+NDOF2*i)=2.0*dh1dh6[0][i];
     127                *(B+NDOF2*numgrids*0+NDOF2*i+1)=dh1dh6[1][i];
     128
     129                *(B+NDOF2*numgrids*1+NDOF2*i)=dh1dh6[0][i];
     130                *(B+NDOF2*numgrids*1+NDOF2*i+1)=2.0*dh1dh6[1][i];
     131
     132                *(B+NDOF2*numgrids*2+NDOF2*i)=dh1dh6[1][i];
     133                *(B+NDOF2*numgrids*2+NDOF2*i+1)=dh1dh6[0][i];
     134
     135                *(B+NDOF2*numgrids*3+NDOF2*i)=dh1dh6[2][i];
     136                *(B+NDOF2*numgrids*3+NDOF2*i+1)=0.0;
     137
     138                *(B+NDOF2*numgrids*4+NDOF2*i)=0.0;
     139                *(B+NDOF2*numgrids*4+NDOF2*i+1)=dh1dh6[2][i];
     140        }
     141}
     142/*}}}*/
     143/*FUNCTION PentaRef::GetBStokes {{{1*/
     144void PentaRef::GetBStokes(double* B, double* xyz_list, double* gauss){
     145
     146        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 3*DOFPERGRID.
     147         * For grid i, Bi can be expressed in the actual coordinate system
     148         * by:          Bi=[ dh/dx          0              0       0  ]
     149         *                                      [   0           dh/dy           0       0  ]
     150         *                                      [   0             0           dh/dy     0  ]
     151         *                                      [ 1/2*dh/dy    1/2*dh/dx        0       0  ]
     152         *                                      [ 1/2*dh/dz       0         1/2*dh/dx   0  ]
     153         *                                      [   0          1/2*dh/dz    1/2*dh/dy   0  ]
     154         *                                      [   0             0             0       h  ]
     155         *                                      [ dh/dx         dh/dy         dh/dz     0  ]
     156         *      where h is the interpolation function for grid i.
     157         *      Same thing for Bb except the last column that does not exist.
     158         */
     159
     160        int i;
     161        const int calculationdof=3;
     162        const int numgrids=6;
     163        int DOFPERGRID=4;
     164
     165        double dh1dh7[calculationdof][numgrids+1];
     166        double l1l6[numgrids];
     167
     168
     169        /*Get dh1dh7 in actual coordinate system: */
     170        GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
     171        GetNodalFunctionsP1(l1l6, gauss);
     172
     173        /*Build B: */
     174        for (i=0;i<numgrids+1;i++){
     175                *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7[0][i]; //B[0][DOFPERGRID*i]=dh1dh6[0][i];
     176                *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
     177                *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
     178                *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
     179                *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7[1][i];
     180                *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
     181                *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
     182                *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
     183                *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7[2][i];
     184                *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=(float).5*dh1dh7[1][i];
     185                *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=(float).5*dh1dh7[0][i];
     186                *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
     187                *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=(float).5*dh1dh7[2][i];
     188                *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
     189                *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=(float).5*dh1dh7[0][i];
     190                *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
     191                *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=(float).5*dh1dh7[2][i];
     192                *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=(float).5*dh1dh7[1][i];
     193                *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=0;
     194                *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=0;
     195                *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=0;
     196                *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=dh1dh7[0][i];
     197                *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=dh1dh7[1][i];
     198                *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=dh1dh7[2][i];
     199        }
     200
     201        for (i=0;i<numgrids;i++){ //last column not for the bubble function
     202                *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
     203                *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
     204                *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
     205                *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
     206                *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
     207                *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
     208                *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=l1l6[i];
     209                *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=0;
     210        }
     211
     212}
     213/*}}}*/
     214/*FUNCTION PentaRef::GetBprimeStokes {{{1*/
     215void PentaRef::GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss){
     216        /*      Compute B'  matrix. B'=[B1' B2' B3' B4' B5' B6' Bb'] where Bi' is of size 3*NDOF2.
     217         *      For grid i, Bi' can be expressed in the actual coordinate system
     218         *      by:
     219         *                              Bi'=[  dh/dx   0          0       0]
     220         *                                       [   0      dh/dy      0       0]
     221         *                                       [   0      0         dh/dz    0]
     222         *                                       [  dh/dy   dh/dx      0       0]
     223         *                                       [  dh/dz   0        dh/dx     0]
     224         *                                       [   0      dh/dz    dh/dy     0]
     225         *                                       [  dh/dx   dh/dy    dh/dz     0]
     226         *                                       [   0      0          0       h]
     227         *      where h is the interpolation function for grid i.
     228         *
     229         *      Same thing for the bubble fonction except that there is no fourth column
     230         */
     231
     232        int i;
     233        const int calculationdof=3;
     234        const int numgrids=6;
     235        int DOFPERGRID=4;
     236
     237        double dh1dh7[calculationdof][numgrids+1];
     238        double l1l6[numgrids];
     239
     240        /*Get dh1dh7 in actual coordinate system: */
     241        GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
     242
     243        GetNodalFunctionsP1(l1l6, gauss);
     244
     245        /*B_primeuild B_prime: */
     246        for (i=0;i<numgrids+1;i++){
     247                *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7[0][i]; //B_prime[0][DOFPERGRID*i]=dh1dh6[0][i];
     248                *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
     249                *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
     250                *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
     251                *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7[1][i];
     252                *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
     253                *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
     254                *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
     255                *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7[2][i];
     256                *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=dh1dh7[1][i];
     257                *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=dh1dh7[0][i];
     258                *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
     259                *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=dh1dh7[2][i];
     260                *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
     261                *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=dh1dh7[0][i];
     262                *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
     263                *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=dh1dh7[2][i];
     264                *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=dh1dh7[1][i];
     265                *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=dh1dh7[0][i];
     266                *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=dh1dh7[1][i];
     267                *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=dh1dh7[2][i];
     268                *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=0;
     269                *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=0;
     270                *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=0;
     271        }
     272
     273        for (i=0;i<numgrids;i++){ //last column not for the bubble function
     274                *(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
     275                *(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
     276                *(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
     277                *(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
     278                *(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
     279                *(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
     280                *(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=0;
     281                *(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=l1l6[i];
     282        }
     283
     284}
     285/*}}}*/
     286/*FUNCTION PentaRef::GetBArtdiff {{{1*/
     287void PentaRef::GetBArtdiff(double* B_artdiff, double* xyz_list, double* gauss){
     288        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
     289         * For grid i, Bi' can be expressed in the actual coordinate system
     290         * by:
     291         *       Bi_artdiff=[ dh/dx ]
     292         *                 [ dh/dy ]
     293         * where h is the interpolation function for grid i.
     294         *
     295         * We assume B has been allocated already, of size: 2x(DOFPERGRID*numgrids)
     296         */
     297
     298        int i;
     299        const int calculationdof=3;
     300        const int numgrids=6;
     301        int DOFPERGRID=1;
     302
     303        /*Same thing in the actual coordinate system: */
     304        double dh1dh6[calculationdof][numgrids];
     305
     306        /*Get dh1dh6 in actual coordinates system : */
     307        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
     308
     309        /*Build B': */
     310        for (i=0;i<numgrids;i++){
     311                *(B_artdiff+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
     312                *(B_artdiff+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
     313        }
     314}
     315/*}}}*/
     316/*FUNCTION PentaRef::GetBAdvec{{{1*/
     317void PentaRef::GetBAdvec(double* B_advec, double* xyz_list, double* gauss){
     318        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
     319         * For grid i, Bi' can be expressed in the actual coordinate system
     320         * by:
     321         *       Bi_advec =[ h ]
     322         *                 [ h ]
     323         *                 [ h ]
     324         * where h is the interpolation function for grid i.
     325         *
     326         * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
     327         */
     328
     329        int i;
     330        int calculationdof=3;
     331        int numgrids=6;
     332        int DOFPERGRID=1;
     333
     334        /*Same thing in the actual coordinate system: */
     335        double l1l6[6];
     336
     337        /*Get dh1dh2dh3 in actual coordinates system : */
     338        GetNodalFunctionsP1(l1l6, gauss);
     339
     340        /*Build B': */
     341        for (i=0;i<numgrids;i++){
     342                *(B_advec+DOFPERGRID*numgrids*0+DOFPERGRID*i)=l1l6[i];
     343                *(B_advec+DOFPERGRID*numgrids*1+DOFPERGRID*i)=l1l6[i];
     344                *(B_advec+DOFPERGRID*numgrids*2+DOFPERGRID*i)=l1l6[i];
     345        }
     346}
     347/*}}}*/
     348/*FUNCTION PentaRef::GetBConduct{{{1*/
     349void PentaRef::GetBConduct(double* B_conduct, double* xyz_list, double* gauss){
     350        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
     351         * For grid i, Bi' can be expressed in the actual coordinate system
     352         * by:
     353         *       Bi_conduct=[ dh/dx ]
     354         *                  [ dh/dy ]
     355         *                  [ dh/dz ]
     356         * where h is the interpolation function for grid i.
     357         *
     358         * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
     359         */
     360
     361        int i;
     362        const int calculationdof=3;
     363        const int numgrids=6;
     364        int DOFPERGRID=1;
     365
     366        /*Same thing in the actual coordinate system: */
     367        double dh1dh6[calculationdof][numgrids];
     368
     369        /*Get dh1dh2dh3 in actual coordinates system : */
     370        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
     371
     372        /*Build B': */
     373        for (i=0;i<numgrids;i++){
     374                *(B_conduct+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
     375                *(B_conduct+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
     376                *(B_conduct+DOFPERGRID*numgrids*2+DOFPERGRID*i)=dh1dh6[2][i];
     377        }
     378}
     379/*}}}*/
     380/*FUNCTION PentaRef::GetBVert{{{1*/
     381void PentaRef::GetBVert(double* B, double* xyz_list, double* gauss){
     382        /*      Compute B  matrix. B=[dh1/dz dh2/dz dh3/dz dh4/dz dh5/dz dh6/dz];
     383                where hi is the interpolation function for grid i.*/
     384
     385        int i;
     386        const int NDOF3=3;
     387        const int numgrids=6;
     388        double dh1dh6[NDOF3][numgrids];
     389
     390        /*Get dh1dh6 in actual coordinate system: */
     391        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss);
     392
     393        /*Build B: */
     394        for (i=0;i<numgrids;i++){
     395                B[i]=dh1dh6[2][i]; 
     396        }
     397
     398}
     399/*}}}*/
     400/*FUNCTION PentaRef::GetBprimeAdvec{{{1*/
     401void PentaRef::GetBprimeAdvec(double* Bprime_advec, double* xyz_list, double* gauss){
     402        /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*DOFPERGRID.
     403         * For grid i, Bi' can be expressed in the actual coordinate system
     404         * by:
     405         *       Biprime_advec=[ dh/dx ]
     406         *                     [ dh/dy ]
     407         *                     [ dh/dz ]
     408         * where h is the interpolation function for grid i.
     409         *
     410         * We assume B has been allocated already, of size: 3x(DOFPERGRID*numgrids)
     411         */
     412
     413        int i;
     414        const int calculationdof=3;
     415        const int numgrids=6;
     416        int DOFPERGRID=1;
     417
     418        /*Same thing in the actual coordinate system: */
     419        double dh1dh6[calculationdof][numgrids];
     420
     421        /*Get dh1dh2dh3 in actual coordinates system : */
     422        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
     423
     424        /*Build B': */
     425        for (i=0;i<numgrids;i++){
     426                *(Bprime_advec+DOFPERGRID*numgrids*0+DOFPERGRID*i)=dh1dh6[0][i];
     427                *(Bprime_advec+DOFPERGRID*numgrids*1+DOFPERGRID*i)=dh1dh6[1][i];
     428                *(Bprime_advec+DOFPERGRID*numgrids*2+DOFPERGRID*i)=dh1dh6[2][i];
     429        }
     430}
     431/*}}}*/
     432/*FUNCTION PentaRef::GetBprimeVert{{{1*/
     433void PentaRef::GetBprimeVert(double* B, double* xyz_list, double* gauss){
     434        /* Compute Bprime  matrix. Bprime=[L1 L2 L3 L4 L5 L6] where Li is the nodal function for grid i*/
     435
     436        GetNodalFunctionsP1(B, gauss);
     437
     438}
     439/*}}}*/
     440/*FUNCTION PentaRef::GetLStokes {{{1*/
     441void PentaRef::GetLStokes(double* LStokes, double* gauss_tria){
     442        /*
     443         * Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof.
     444         * For grid i, Li can be expressed in the actual coordinate system
     445         * by:
     446         *       Li=[ h    0    0   0]
     447         *                    [ 0    h    0   0]
     448         *                    [ 0    0    h   0]
     449         *                    [ 0    0    h   0]
     450         *                    [ h    0    0   0]
     451         *                    [ 0    h    0   0]
     452         *                    [ h    0    0   0]
     453         *                    [ 0    h    0   0]
     454         *                    [ 0    0    h   0]
     455         *                    [ 0    0    h   0]
     456         *                    [ 0    0    h   0]
     457         *                    [ h    0    0   0]
     458         *                    [ 0    h    0   0]
     459         *                    [ 0    0    h   0]
     460         * where h is the interpolation function for grid i.
     461         */
     462
     463        int i;
     464        const int numgrids2d=3;
     465        int num_dof=4;
     466
     467        double l1l2l3[numgrids2d];
     468
     469
     470        /*Get l1l2l3 in actual coordinate system: */
     471        l1l2l3[0]=gauss_tria[0];
     472        l1l2l3[1]=gauss_tria[1];
     473        l1l2l3[2]=gauss_tria[2];
     474
     475        /*Build LStokes: */
     476        for (i=0;i<3;i++){
     477                *(LStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LStokes[0][NDOF2*i]=dh1dh3[0][i];
     478                *(LStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
     479                *(LStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
     480                *(LStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
     481                *(LStokes+num_dof*numgrids2d*1+num_dof*i)=0;
     482                *(LStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
     483                *(LStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
     484                *(LStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
     485                *(LStokes+num_dof*numgrids2d*2+num_dof*i)=0;
     486                *(LStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
     487                *(LStokes+num_dof*numgrids2d*2+num_dof*i+2)=l1l2l3[i];
     488                *(LStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
     489                *(LStokes+num_dof*numgrids2d*3+num_dof*i)=0;
     490                *(LStokes+num_dof*numgrids2d*3+num_dof*i+1)=0;
     491                *(LStokes+num_dof*numgrids2d*3+num_dof*i+2)=l1l2l3[i];
     492                *(LStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
     493                *(LStokes+num_dof*numgrids2d*4+num_dof*i)=l1l2l3[i];
     494                *(LStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
     495                *(LStokes+num_dof*numgrids2d*4+num_dof*i+2)=0;
     496                *(LStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
     497                *(LStokes+num_dof*numgrids2d*5+num_dof*i)=0;
     498                *(LStokes+num_dof*numgrids2d*5+num_dof*i+1)=l1l2l3[i];
     499                *(LStokes+num_dof*numgrids2d*5+num_dof*i+2)=0;
     500                *(LStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
     501                *(LStokes+num_dof*numgrids2d*6+num_dof*i)=l1l2l3[i];
     502                *(LStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
     503                *(LStokes+num_dof*numgrids2d*6+num_dof*i+2)=0;
     504                *(LStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
     505                *(LStokes+num_dof*numgrids2d*7+num_dof*i)=0;
     506                *(LStokes+num_dof*numgrids2d*7+num_dof*i+1)=l1l2l3[i];
     507                *(LStokes+num_dof*numgrids2d*7+num_dof*i+2)=0;
     508                *(LStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
     509                *(LStokes+num_dof*numgrids2d*8+num_dof*i)=0;
     510                *(LStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
     511                *(LStokes+num_dof*numgrids2d*8+num_dof*i+2)=l1l2l3[i];
     512                *(LStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
     513                *(LStokes+num_dof*numgrids2d*9+num_dof*i)=0;
     514                *(LStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
     515                *(LStokes+num_dof*numgrids2d*9+num_dof*i+2)=l1l2l3[i];
     516                *(LStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
     517                *(LStokes+num_dof*numgrids2d*10+num_dof*i)=0;
     518                *(LStokes+num_dof*numgrids2d*10+num_dof*i+1)=0;
     519                *(LStokes+num_dof*numgrids2d*10+num_dof*i+2)=l1l2l3[i];
     520                *(LStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
     521                *(LStokes+num_dof*numgrids2d*11+num_dof*i)=l1l2l3[i];
     522                *(LStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
     523                *(LStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
     524                *(LStokes+num_dof*numgrids2d*11+num_dof*i+3)=0;
     525                *(LStokes+num_dof*numgrids2d*12+num_dof*i)=0;
     526                *(LStokes+num_dof*numgrids2d*12+num_dof*i+1)=l1l2l3[i];
     527                *(LStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
     528                *(LStokes+num_dof*numgrids2d*12+num_dof*i+3)=0;
     529                *(LStokes+num_dof*numgrids2d*13+num_dof*i)=0;
     530                *(LStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
     531                *(LStokes+num_dof*numgrids2d*13+num_dof*i+2)=l1l2l3[i];
     532                *(LStokes+num_dof*numgrids2d*13+num_dof*i+3)=0;
     533
     534        }
     535}
     536/*}}}*/
     537/*FUNCTION PentaRef::GetLprimeStokes {{{1*/
     538void PentaRef::GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_tria, double* gauss){
     539
     540        /*
     541         * Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof.
     542         * For grid i, Lpi can be expressed in the actual coordinate system
     543         * by:
     544         *       Lpi=[ h    0    0   0]
     545         *                     [ 0    h    0   0]
     546         *                     [ h    0    0   0]
     547         *                     [ 0    h    0   0]
     548         *                     [ 0    0    h   0]
     549         *                     [ 0    0    h   0]
     550         *                     [ 0    0  dh/dz 0]
     551         *                     [ 0    0  dh/dz 0]
     552         *                     [ 0    0  dh/dz 0]
     553         *                     [dh/dz 0  dh/dx 0]
     554         *                     [ 0 dh/dz dh/dy 0]
     555         *           [ 0    0    0   h]
     556         *           [ 0    0    0   h]
     557         *           [ 0    0    0   h]
     558         * where h is the interpolation function for grid i.
     559         */
     560        int i;
     561        const int numgrids2d=3;
     562        int num_dof=4;
     563
     564        double l1l2l3[numgrids2d];
     565        double dh1dh6[3][6];
     566
     567        /*Get l1l2l3 in actual coordinate system: */
     568        l1l2l3[0]=gauss_tria[0];
     569        l1l2l3[1]=gauss_tria[1];
     570        l1l2l3[2]=gauss_tria[2];
     571
     572        GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
     573
     574        /*Build LprimeStokes: */
     575        for (i=0;i<3;i++){
     576                *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh3[0][i];
     577                *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
     578                *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
     579                *(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
     580                *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i)=0;
     581                *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
     582                *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
     583                *(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
     584                *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i)=l1l2l3[i];
     585                *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
     586                *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+2)=0;
     587                *(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
     588                *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i)=0;
     589                *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+1)=l1l2l3[i];
     590                *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+2)=0;
     591                *(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
     592                *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i)=0;
     593                *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
     594                *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+2)=l1l2l3[i];
     595                *(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
     596                *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i)=0;
     597                *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+1)=0;
     598                *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+2)=l1l2l3[i];
     599                *(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
     600                *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i)=0;
     601                *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
     602                *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+2)=dh1dh6[2][i];
     603                *(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
     604                *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i)=0;
     605                *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+1)=0;
     606                *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+2)=dh1dh6[2][i];
     607                *(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
     608                *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i)=0;
     609                *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
     610                *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+2)=dh1dh6[2][i];
     611                *(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
     612                *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i)=dh1dh6[2][i];
     613                *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
     614                *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+2)=dh1dh6[0][i];
     615                *(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
     616                *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i)=0;
     617                *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+1)=dh1dh6[2][i];
     618                *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+2)=dh1dh6[1][i];
     619                *(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
     620                *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i)=0;
     621                *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
     622                *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
     623                *(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+3)=l1l2l3[i];
     624                *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i)=0;
     625                *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+1)=0;
     626                *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
     627                *(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+3)=l1l2l3[i];
     628                *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i)=0;
     629                *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
     630                *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+2)=0;
     631                *(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+3)=l1l2l3[i];
     632
     633        }
     634}
     635/*}}}*/
     636/*FUNCTION PentaRef::GetJacobian {{{1*/
     637void PentaRef::GetJacobian(double* J, double* xyz_list,double* gauss){
     638
     639        const int NDOF3=3;
     640        int i,j;
     641
     642        /*The Jacobian is constant over the element, discard the gaussian points.
     643         * J is assumed to have been allocated of size NDOF2xNDOF2.*/
     644
     645        double A1,A2,A3; //area coordinates
     646        double xi,eta,zi; //parametric coordinates
     647
     648        double x1,x2,x3,x4,x5,x6;
     649        double y1,y2,y3,y4,y5,y6;
     650        double z1,z2,z3,z4,z5,z6;
     651
     652        /*Figure out xi,eta and zi (parametric coordinates), for this gaussian point: */
     653        A1=gauss[0];
     654        A2=gauss[1];
     655        A3=gauss[2];
     656
     657        xi=A2-A1;
     658        eta=SQRT3*A3;
     659        zi=gauss[3];
     660
     661        x1=*(xyz_list+3*0+0);
     662        x2=*(xyz_list+3*1+0);
     663        x3=*(xyz_list+3*2+0);
     664        x4=*(xyz_list+3*3+0);
     665        x5=*(xyz_list+3*4+0);
     666        x6=*(xyz_list+3*5+0);
     667
     668        y1=*(xyz_list+3*0+1);
     669        y2=*(xyz_list+3*1+1);
     670        y3=*(xyz_list+3*2+1);
     671        y4=*(xyz_list+3*3+1);
     672        y5=*(xyz_list+3*4+1);
     673        y6=*(xyz_list+3*5+1);
     674
     675        z1=*(xyz_list+3*0+2);
     676        z2=*(xyz_list+3*1+2);
     677        z3=*(xyz_list+3*2+2);
     678        z4=*(xyz_list+3*3+2);
     679        z5=*(xyz_list+3*4+2);
     680        z6=*(xyz_list+3*5+2);
     681
     682        *(J+NDOF3*0+0)=0.25*(x1-x2-x4+x5)*zi+0.25*(-x1+x2-x4+x5);
     683        *(J+NDOF3*1+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*zi+SQRT3/12.0*(-x1-x2+2*x3-x4-x5+2*x6);
     684        *(J+NDOF3*2+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*eta+1/4*(x1-x2-x4+x5)*xi +0.25*(-x1+x5-x2+x4);
     685
     686        *(J+NDOF3*0+1)=0.25*(y1-y2-y4+y5)*zi+0.25*(-y1+y2-y4+y5);
     687        *(J+NDOF3*1+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*zi+SQRT3/12.0*(-y1-y2+2*y3-y4-y5+2*y6);
     688        *(J+NDOF3*2+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*eta+0.25*(y1-y2-y4+y5)*xi+0.25*(y4-y1+y5-y2);
     689
     690        *(J+NDOF3*0+2)=0.25*(z1-z2-z4+z5)*zi+0.25*(-z1+z2-z4+z5);
     691        *(J+NDOF3*1+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*zi+SQRT3/12.0*(-z1-z2+2*z3-z4-z5+2*z6);
     692        *(J+NDOF3*2+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*eta+0.25*(z1-z2-z4+z5)*xi+0.25*(-z1+z5-z2+z4);
     693
     694}
     695/*}}}*/
     696/*FUNCTION PentaRef::GetJacobianDeterminant {{{1*/
     697void PentaRef::GetJacobianDeterminant(double*  Jdet, double* xyz_list,double* gauss){
     698        /*On a penta, Jacobian varies according to coordinates. We need to get the Jacobian, and take
     699         * the determinant of it: */
     700        const int NDOF3=3;
     701        double J[NDOF3][NDOF3];
     702
     703        GetJacobian(&J[0][0],xyz_list,gauss);
     704
     705        *Jdet= J[0][0]*J[1][1]*J[2][2]-J[0][0]*J[1][2]*J[2][1]-J[1][0]*J[0][1]*J[2][2]+J[1][0]*J[0][2]*J[2][1]+J[2][0]*J[0][1]*J[1][2]-J[2][0]*J[0][2]*J[1][1];
     706
     707        if(*Jdet<0){
     708                ISSMERROR("negative jacobian determinant!");
     709        }
     710}
     711/*}}}*/
     712/*FUNCTION PentaRef::GetJacobianInvert {{{1*/
     713void PentaRef::GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss){
     714
     715        double Jdet;
     716        const int NDOF3=3;
     717
     718        /*Call Jacobian routine to get the jacobian:*/
     719        GetJacobian(Jinv, xyz_list, gauss);
     720
     721        /*Invert Jacobian matrix: */
     722        MatrixInverse(Jinv,NDOF3,NDOF3,NULL,0,&Jdet);
     723}
     724/*}}}*/
     725/*FUNCTION PentaRef::GetNodalFunctionsMINI{{{1*/
     726void PentaRef::GetNodalFunctionsMINI(double* l1l7, double* gauss){
     727        /*This routine returns the values of the nodal functions  at the gaussian point.*/
     728
     729        l1l7[0]=gauss[0]*(1.0-gauss[3])/2.0;
     730        l1l7[1]=gauss[1]*(1.0-gauss[3])/2.0;
     731        l1l7[2]=gauss[2]*(1.0-gauss[3])/2.0;
     732        l1l7[3]=gauss[0]*(1.0+gauss[3])/2.0;
     733        l1l7[4]=gauss[1]*(1.0+gauss[3])/2.0;
     734        l1l7[5]=gauss[2]*(1.0+gauss[3])/2.0;
     735        l1l7[6]=27*gauss[0]*gauss[1]*gauss[2]*(1.0+gauss[3])*(1.0-gauss[3]);
     736
     737}
     738/*}}}*/
     739/*FUNCTION PentaRef::GetNodalFunctionsMINIDerivatives{{{1*/
     740void PentaRef::GetNodalFunctionsMINIDerivatives(double* dh1dh7,double* xyz_list, double* gauss){
     741
     742        /*This routine returns the values of the nodal functions derivatives  (with respect to the
     743         * actual coordinate system): */
     744
     745        int       i;
     746        const int numgrids = 7;
     747        double    dh1dh7_ref[3][numgrids];
     748        double    Jinv[3][3];
     749
     750        /*Get derivative values with respect to parametric coordinate system: */
     751        GetNodalFunctionsMINIDerivativesReference(&dh1dh7_ref[0][0], gauss);
     752
     753        /*Get Jacobian invert: */
     754        GetJacobianInvert(&Jinv[0][0], xyz_list, gauss);
     755
     756        /*Build dh1dh6:
     757         *
     758         * [dhi/dx]= Jinv'*[dhi/dr]
     759         * [dhi/dy]        [dhi/ds]
     760         * [dhi/dz]        [dhi/dzeta]
     761         */
     762
     763        for (i=0;i<numgrids;i++){
     764                *(dh1dh7+numgrids*0+i)=Jinv[0][0]*dh1dh7_ref[0][i]+Jinv[0][1]*dh1dh7_ref[1][i]+Jinv[0][2]*dh1dh7_ref[2][i];
     765                *(dh1dh7+numgrids*1+i)=Jinv[1][0]*dh1dh7_ref[0][i]+Jinv[1][1]*dh1dh7_ref[1][i]+Jinv[1][2]*dh1dh7_ref[2][i];
     766                *(dh1dh7+numgrids*2+i)=Jinv[2][0]*dh1dh7_ref[0][i]+Jinv[2][1]*dh1dh7_ref[1][i]+Jinv[2][2]*dh1dh7_ref[2][i];
     767        }
     768
     769}
     770/*}}}*/
     771/*FUNCTION PentaRef::GetNodalFunctionsMINIDerivativesReference{{{1*/
     772void PentaRef::GetNodalFunctionsMINIDerivativesReference(double* dl1dl7,double* gauss){
     773
     774        /*This routine returns the values of the nodal functions derivatives  (with respect to the
     775         * natural coordinate system) at the gaussian point. */
     776
     777        int    numgrids=7; //six plus bubble grids
     778
     779        double r=gauss[1]-gauss[0];
     780        double s=-3.0/SQRT3*(gauss[0]+gauss[1]-2.0/3.0);
     781        double zeta=gauss[3];
     782
     783        /*First nodal function: */
     784        *(dl1dl7+numgrids*0+0)=-0.5*(1.0-zeta)/2.0;
     785        *(dl1dl7+numgrids*1+0)=-SQRT3/6.0*(1.0-zeta)/2.0;
     786        *(dl1dl7+numgrids*2+0)=-0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
     787
     788        /*Second nodal function: */
     789        *(dl1dl7+numgrids*0+1)=0.5*(1.0-zeta)/2.0;
     790        *(dl1dl7+numgrids*1+1)=-SQRT3/6.0*(1.0-zeta)/2.0;
     791        *(dl1dl7+numgrids*2+1)=-0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
     792
     793        /*Third nodal function: */
     794        *(dl1dl7+numgrids*0+2)=0;
     795        *(dl1dl7+numgrids*1+2)=SQRT3/3.0*(1.0-zeta)/2.0;
     796        *(dl1dl7+numgrids*2+2)=-0.5*(SQRT3/3.0*s+ONETHIRD);
     797
     798        /*Fourth nodal function: */
     799        *(dl1dl7+numgrids*0+3)=-0.5*(1.0+zeta)/2.0;
     800        *(dl1dl7+numgrids*1+3)=-SQRT3/6.0*(1.0+zeta)/2.0;
     801        *(dl1dl7+numgrids*2+3)=0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
     802
     803        /*Fith nodal function: */
     804        *(dl1dl7+numgrids*0+4)=0.5*(1.0+zeta)/2.0;
     805        *(dl1dl7+numgrids*1+4)=-SQRT3/6.0*(1.0+zeta)/2.0;
     806        *(dl1dl7+numgrids*2+4)=0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
     807
     808        /*Sixth nodal function: */
     809        *(dl1dl7+numgrids*0+5)=0;
     810        *(dl1dl7+numgrids*1+5)=SQRT3/3.0*(1.0+zeta)/2.0;
     811        *(dl1dl7+numgrids*2+5)=0.5*(SQRT3/3.0*s+ONETHIRD);
     812
     813        /*Seventh nodal function: */
     814        *(dl1dl7+numgrids*0+6)=9.0/2.0*r*(1.0+zeta)*(zeta-1.0)*(SQRT3*s+1.0);
     815        *(dl1dl7+numgrids*1+6)=9.0/4.0*(1+zeta)*(1-zeta)*(SQRT3*pow(s,2.0)-2.0*s-SQRT3*pow(r,2.0));
     816        *(dl1dl7+numgrids*2+6)=27*gauss[0]*gauss[1]*gauss[2]*(-2.0*zeta);
     817
     818}
     819/*}}}*/
     820/*FUNCTION PentaRef::GetNodalFunctionsP1 {{{1*/
     821void PentaRef::GetNodalFunctionsP1(double* l1l6, double* gauss){
     822        /*This routine returns the values of the nodal functions  at the gaussian point.*/
     823
     824        l1l6[0]=gauss[0]*(1-gauss[3])/2.0;
     825        l1l6[1]=gauss[1]*(1-gauss[3])/2.0;
     826        l1l6[2]=gauss[2]*(1-gauss[3])/2.0;
     827        l1l6[3]=gauss[0]*(1+gauss[3])/2.0;
     828        l1l6[4]=gauss[1]*(1+gauss[3])/2.0;
     829        l1l6[5]=gauss[2]*(1+gauss[3])/2.0;
     830
     831}
     832/*}}}*/
     833/*FUNCTION PentaRef::GetNodalFunctionsP1Derivatives {{{1*/
     834void PentaRef::GetNodalFunctionsP1Derivatives(double* dh1dh6,double* xyz_list, double* gauss){
     835
     836        /*This routine returns the values of the nodal functions derivatives  (with respect to the
     837         * actual coordinate system): */
     838        int       i;
     839        const int NDOF3    = 3;
     840        const int numgrids = 6;
     841        double    dh1dh6_ref[NDOF3][numgrids];
     842        double    Jinv[NDOF3][NDOF3];
     843
     844        /*Get derivative values with respect to parametric coordinate system: */
     845        GetNodalFunctionsP1DerivativesReference(&dh1dh6_ref[0][0], gauss);
     846
     847        /*Get Jacobian invert: */
     848        GetJacobianInvert(&Jinv[0][0], xyz_list, gauss);
     849
     850        /*Build dh1dh3:
     851         *
     852         * [dhi/dx]= Jinv*[dhi/dr]
     853         * [dhi/dy]       [dhi/ds]
     854         * [dhi/dz]       [dhi/dn]
     855         */
     856
     857        for (i=0;i<numgrids;i++){
     858                *(dh1dh6+numgrids*0+i)=Jinv[0][0]*dh1dh6_ref[0][i]+Jinv[0][1]*dh1dh6_ref[1][i]+Jinv[0][2]*dh1dh6_ref[2][i];
     859                *(dh1dh6+numgrids*1+i)=Jinv[1][0]*dh1dh6_ref[0][i]+Jinv[1][1]*dh1dh6_ref[1][i]+Jinv[1][2]*dh1dh6_ref[2][i];
     860                *(dh1dh6+numgrids*2+i)=Jinv[2][0]*dh1dh6_ref[0][i]+Jinv[2][1]*dh1dh6_ref[1][i]+Jinv[2][2]*dh1dh6_ref[2][i];
     861        }
     862
     863}
     864/*}}}*/
     865/*FUNCTION PentaRef::GetNodalFunctionsP1DerivativesReference {{{1*/
     866void PentaRef::GetNodalFunctionsP1DerivativesReference(double* dl1dl6,double* gauss){
     867
     868        /*This routine returns the values of the nodal functions derivatives  (with respect to the
     869         * natural coordinate system) at the gaussian point. Those values vary along xi,eta,z */
     870
     871        const int numgrids=6;
     872        double A1,A2,A3,z;
     873
     874        A1=gauss[0]; //first area coordinate value. In term of xi and eta: A1=(1-xi)/2-eta/(2*SQRT3);
     875        A2=gauss[1]; //second area coordinate value In term of xi and eta: A2=(1+xi)/2-eta/(2*SQRT3);
     876        A3=gauss[2]; //third area coordinate value  In term of xi and eta: A3=y/SQRT3;
     877        z=gauss[3]; //fourth vertical coordinate value. Corresponding nodal function: (1-z)/2 and (1+z)/2
     878
     879
     880        /*First nodal function derivatives. The corresponding nodal function is N=A1*(1-z)/2. Its derivatives follow*/
     881        *(dl1dl6+numgrids*0+0)=-0.5*(1.0-z)/2.0;
     882        *(dl1dl6+numgrids*1+0)=-0.5/SQRT3*(1.0-z)/2.0;
     883        *(dl1dl6+numgrids*2+0)=-0.5*A1;
     884
     885        /*Second nodal function: The corresponding nodal function is N=A2*(1-z)/2. Its derivatives follow*/
     886        *(dl1dl6+numgrids*0+1)=0.5*(1.0-z)/2.0;
     887        *(dl1dl6+numgrids*1+1)=-0.5/SQRT3*(1.0-z)/2.0;
     888        *(dl1dl6+numgrids*2+1)=-0.5*A2;
     889
     890        /*Third nodal function: The corresponding nodal function is N=A3*(1-z)/2. Its derivatives follow*/
     891        *(dl1dl6+numgrids*0+2)=0.0;
     892        *(dl1dl6+numgrids*1+2)=1.0/SQRT3*(1.0-z)/2.0;
     893        *(dl1dl6+numgrids*2+2)=-0.5*A3;
     894
     895        /*Fourth nodal function: The corresponding nodal function is N=A1*(1+z)/2. Its derivatives follow*/
     896        *(dl1dl6+numgrids*0+3)=-0.5*(1.0+z)/2.0;
     897        *(dl1dl6+numgrids*1+3)=-0.5/SQRT3*(1.0+z)/2.0;
     898        *(dl1dl6+numgrids*2+3)=0.5*A1;
     899
     900        /*Fifth nodal function: The corresponding nodal function is N=A2*(1+z)/2. Its derivatives follow*/
     901        *(dl1dl6+numgrids*0+4)=0.5*(1.0+z)/2.0;
     902        *(dl1dl6+numgrids*1+4)=-0.5/SQRT3*(1.0+z)/2.0;
     903        *(dl1dl6+numgrids*2+4)=0.5*A2;
     904
     905        /*Sixth nodal function: The corresponding nodal function is N=A3*(1+z)/2. Its derivatives follow*/
     906        *(dl1dl6+numgrids*0+5)=0.0;
     907        *(dl1dl6+numgrids*1+5)=1.0/SQRT3*(1.0+z)/2.0;
     908        *(dl1dl6+numgrids*2+5)=0.5*A3;
     909}
     910/*}}}*/
  • issm/trunk/src/c/objects/Elements/PentaRef.h

    r4882 r4885  
    2323
    2424                /*Numerics*/
     25                void GetNodalFunctionsP1(double* l1l6, double* gauss);
     26                void GetNodalFunctionsMINI(double* l1l7, double* gauss);
     27                void GetNodalFunctionsP1Derivatives(double* dh1dh6,double* xyz_list, double* gauss);
     28                void GetNodalFunctionsMINIDerivatives(double* dh1dh7,double* xyz_list, double* gauss);
     29                void GetNodalFunctionsP1DerivativesReference(double* dl1dl6,double* gauss);
     30                void GetNodalFunctionsMINIDerivativesReference(double* dl1dl7,double* gauss);
     31                void GetJacobian(double* J, double* xyz_list,double* gauss);
     32                void GetJacobianDeterminant(double*  Jdet, double* xyz_list,double* gauss);
     33                void GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss);
     34                void GetBPattyn(double* B, double* xyz_list, double* gauss);
     35                void GetBprimePattyn(double* B, double* xyz_list, double* gauss);
     36                void GetBStokes(double* B, double* xyz_list, double* gauss);
     37                void GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss);
     38                void GetBprimeVert(double* B, double* xyz_list, double* gauss);
     39                void GetBAdvec(double* B_advec, double* xyz_list, double* gauss);
     40                void GetBArtdiff(double* B_artdiff, double* xyz_list, double* gauss);
     41                void GetBConduct(double* B_conduct, double* xyz_list, double* gauss);
     42                void GetBVert(double* B, double* xyz_list, double* gauss);
     43                void GetBprimeAdvec(double* Bprime_advec, double* xyz_list, double* gauss);
     44                void GetLStokes(double* LStokes, double* gauss_tria);
     45                void GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_tria, double* gauss);
    2546
    2647};
  • issm/trunk/src/c/objects/Elements/Tria.cpp

    r4882 r4885  
    146146        int i;
    147147        int flaghook;
    148         int type;
    149148
    150149        /*recover marshalled_dataset: */
     
    158157        /*demarshall Ref: */
    159158        this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
    160         for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(type));marshalled_dataset+=sizeof(type);}
     159        for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
    161160
    162161        /*allocate dynamic memory: */
     
    23732372
    23742373                /*Get B  and B prime matrix: */
    2375                 GetB_prog(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    2376                 GetBPrime_prog(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2374                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2375                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    23772376
    23782377                //Get vx, vy and their derivatives at gauss point
     
    25062505                /*Get B  and B prime matrix: */
    25072506                /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
    2508                 GetB_prog(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    2509                 GetBPrime_prog(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2507                GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2508                GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    25102509
    25112510                //Get vx, vy and their derivatives at gauss point
     
    26562655
    26572656                /*Get B  and B prime matrix: */
    2658                 GetB_prog(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    2659                 GetBPrime_prog(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2657                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2658                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    26602659
    26612660                //Get vx, vy and their derivatives at gauss point
     
    28292828
    28302829                /*Get B and Bprime matrices: */
    2831                 GetB(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    2832                 GetBPrime(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2830                GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     2831                GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    28332832
    28342833                /*  Do the triple product tB*D*Bprime: */
     
    33383337
    33393338                /*Get B  and B prime matrix: */
    3340                 GetB_prog(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    3341                 GetBPrime_prog(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     3339                GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     3340                GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    33423341
    33433342                //Get vx, vy and their derivatives at gauss point
     
    34923491                /*Get B  and B prime matrix: */
    34933492                /*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
    3494                 GetB_prog(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
    3495                 GetBPrime_prog(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
     3493                GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss_l1l2l3);
     3494                GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss_l1l2l3);
    34963495
    34973496                //Get vx, vy and their derivatives at gauss point
  • issm/trunk/src/c/objects/Elements/TriaRef.cpp

    r4770 r4885  
    5252
    5353/*Reference Element numerics*/
    54 /*FUNCTION TriaRef::GetB {{{1*/
    55 void TriaRef::GetB(double* B, double* xyz_list, double* gauss){
     54/*FUNCTION TriaRef::GetBMacAyeal {{{1*/
     55void TriaRef::GetBMacAyeal(double* B, double* xyz_list, double* gauss){
    5656        /*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2.
    5757         * For grid i, Bi can be expressed in the actual coordinate system
     
    8686}
    8787/*}}}*/
    88 /*FUNCTION TriaRef::GetB_prog {{{1*/
    89 void TriaRef::GetB_prog(double* B_prog, double* xyz_list, double* gauss){
     88/*FUNCTION TriaRef::GetBPrognostic{{{1*/
     89void TriaRef::GetBPrognostic(double* B_prog, double* xyz_list, double* gauss){
    9090        /*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2.
    9191         * For grid i, Bi can be expressed in the actual coordinate system
     
    115115}
    116116/*}}}*/
    117 /*FUNCTION TriaRef::GetBPrime {{{1*/
    118 void TriaRef::GetBPrime(double* Bprime, double* xyz_list, double* gauss){
     117/*FUNCTION TriaRef::GetBprimeMacAyeal {{{1*/
     118void TriaRef::GetBprimeMacAyeal(double* Bprime, double* xyz_list, double* gauss){
    119119
    120120        /*Compute B'  matrix. B'=[B1' B2' B3'] where Bi' is of size 3*NDOF2.
     
    150150}
    151151/*}}}*/
    152 /*FUNCTION TriaRef::GetBPrime_prog {{{1*/
    153 void TriaRef::GetBPrime_prog(double* Bprime_prog, double* xyz_list, double* gauss){
     152/*FUNCTION TriaRef::GetBprimePrognostic{{{1*/
     153void TriaRef::GetBprimePrognostic(double* Bprime_prog, double* xyz_list, double* gauss){
    154154        /*Compute B'  matrix. B'=[B1' B2' B3'] where Bi' is of size 3*NDOF2.
    155155         * For grid i, Bi' can be expressed in the actual coordinate system
    156156         * by:
    157157         *       Bi_prime=[ dh/dx ]
    158          *                       [ dh/dy ]
     158         *                [ dh/dy ]
    159159         * where h is the interpolation function for grid i.
    160160         *
     
    186186         * by:
    187187         *       numdof=1:
    188          *       Li=h;
     188         *                 Li=h;
    189189         *       numdof=2:
    190          *       Li=[ h    0    ]
    191          *                [   0   h ]
     190         *                 Li=[ h   0 ]
     191         *                    [ 0   h ]
    192192         * where h is the interpolation function for grid i.
    193193         *
     
    310310/*FUNCTION TriaRef::GetNodalFunctions {{{1*/
    311311void TriaRef::GetNodalFunctions(double* l1l2l3, double* gauss){
    312 
    313312        /*This routine returns the values of the nodal functions  at the gaussian point.*/
    314313
    315         /*First nodal function: */
    316314        l1l2l3[0]=gauss[0];
    317 
    318         /*Second nodal function: */
    319315        l1l2l3[1]=gauss[1];
    320 
    321         /*Third nodal function: */
    322316        l1l2l3[2]=gauss[2];
    323317
     
    328322
    329323        /*This routine returns the values of the nodal functions derivatives  (with respect to the
    330          * actual coordinate system: */
    331         int i;
    332         const int NDOF2=2;
    333         const int numgrids=3;
    334         double dh1dh3_ref[NDOF2][numgrids];
    335         double Jinv[NDOF2][NDOF2];
     324         * actual coordinate system): */
     325        int       i;
     326        const int NDOF2    = 2;
     327        const int numgrids = 3;
     328        double    dh1dh3_ref[NDOF2][numgrids];
     329        double    Jinv[NDOF2][NDOF2];
    336330
    337331        /*Get derivative values with respect to parametric coordinate system: */
  • issm/trunk/src/c/objects/Elements/TriaRef.h

    r4770 r4885  
    2323
    2424                /*Numerics*/
    25                 void GetB(double* B, double* xyz_list, double* gauss);
    26                 void GetBPrime(double* Bprime, double* xyz_list, double* gauss);
    27                 void GetBPrime_prog(double* Bprime_prog, double* xyz_list, double* gauss);
    28                 void GetB_prog(double* B_prog, double* xyz_list, double* gauss);
     25                void GetBMacAyeal(double* B, double* xyz_list, double* gauss);
     26                void GetBprimeMacAyeal(double* Bprime, double* xyz_list, double* gauss);
     27                void GetBprimePrognostic(double* Bprime_prog, double* xyz_list, double* gauss);
     28                void GetBPrognostic(double* B_prog, double* xyz_list, double* gauss);
    2929                void GetL(double* L, double* xyz_list, double* gauss,int numdof);
    3030                void GetJacobian(double* J, double* xyz_list,double* gauss);
  • issm/trunk/src/c/objects/Inputs/PentaVertexInput.cpp

    r4882 r4885  
    481481
    482482/*Intermediary*/
    483 /*FUNCTION PentaVertexInput::GetNodalFunctionsP1 {{{1*/
    484 void PentaVertexInput::GetNodalFunctionsP1(double* l1l6, double* gauss_coord){
    485 
    486         /*This routine returns the values of the nodal functions  at the gaussian point.*/
    487 
    488         l1l6[0]=gauss_coord[0]*(1-gauss_coord[3])/2.0;
    489 
    490         l1l6[1]=gauss_coord[1]*(1-gauss_coord[3])/2.0;
    491 
    492         l1l6[2]=gauss_coord[2]*(1-gauss_coord[3])/2.0;
    493 
    494         l1l6[3]=gauss_coord[0]*(1+gauss_coord[3])/2.0;
    495 
    496         l1l6[4]=gauss_coord[1]*(1+gauss_coord[3])/2.0;
    497 
    498         l1l6[5]=gauss_coord[2]*(1+gauss_coord[3])/2.0;
    499 
    500 }
    501 /*}}}*/
    502 /*FUNCTION PentaVertexInput::GetNodalFunctionsMINI{{{1*/
    503 void PentaVertexInput::GetNodalFunctionsMINI(double* l1l7, double* gauss_coord){
    504 
    505         /*This routine returns the values of the nodal functions  at the gaussian point.*/
    506 
    507         /*First nodal function: */
    508         l1l7[0]=gauss_coord[0]*(1.0-gauss_coord[3])/2.0;
    509 
    510         /*Second nodal function: */
    511         l1l7[1]=gauss_coord[1]*(1.0-gauss_coord[3])/2.0;
    512 
    513         /*Third nodal function: */
    514         l1l7[2]=gauss_coord[2]*(1.0-gauss_coord[3])/2.0;
    515 
    516         /*Fourth nodal function: */
    517         l1l7[3]=gauss_coord[0]*(1.0+gauss_coord[3])/2.0;
    518 
    519         /*Fifth nodal function: */
    520         l1l7[4]=gauss_coord[1]*(1.0+gauss_coord[3])/2.0;
    521 
    522         /*Sixth nodal function: */
    523         l1l7[5]=gauss_coord[2]*(1.0+gauss_coord[3])/2.0;
    524 
    525         /*Seventh nodal function: */
    526         l1l7[6]=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(1.0+gauss_coord[3])*(1.0-gauss_coord[3]);
    527 
    528 }
    529 /*}}}*/
    530 /*FUNCTION PentaVertexInput::GetNodalFunctionsP1Derivatives {{{1*/
    531 void PentaVertexInput::GetNodalFunctionsP1Derivatives(double* dh1dh6,double* xyz_list, double* gauss_coord){
    532 
    533         /*This routine returns the values of the nodal functions derivatives  (with respect to the actual coordinate system: */
    534         int i;
    535         const int NDOF3=3;
    536         const int numgrids=6;
    537 
    538         double dh1dh6_ref[NDOF3][numgrids];
    539         double Jinv[NDOF3][NDOF3];
    540 
    541         /*Get derivative values with respect to parametric coordinate system: */
    542         GetNodalFunctionsP1DerivativesReference(&dh1dh6_ref[0][0], gauss_coord);
    543 
    544         /*Get Jacobian invert: */
    545         GetJacobianInvert(&Jinv[0][0], xyz_list, gauss_coord);
    546 
    547         /*Build dh1dh3:
    548          *
    549          * [dhi/dx]= Jinv*[dhi/dr]
    550          * [dhi/dy]       [dhi/ds]
    551          * [dhi/dz]       [dhi/dn]
    552          */
    553 
    554         for (i=0;i<numgrids;i++){
    555                 *(dh1dh6+numgrids*0+i)=Jinv[0][0]*dh1dh6_ref[0][i]+Jinv[0][1]*dh1dh6_ref[1][i]+Jinv[0][2]*dh1dh6_ref[2][i];
    556                 *(dh1dh6+numgrids*1+i)=Jinv[1][0]*dh1dh6_ref[0][i]+Jinv[1][1]*dh1dh6_ref[1][i]+Jinv[1][2]*dh1dh6_ref[2][i];
    557                 *(dh1dh6+numgrids*2+i)=Jinv[2][0]*dh1dh6_ref[0][i]+Jinv[2][1]*dh1dh6_ref[1][i]+Jinv[2][2]*dh1dh6_ref[2][i];
    558         }
    559 
    560 }
    561 /*}}}*/
    562 /*FUNCTION PentaVertexInput::GetNodalFunctionsMINIDerivatives{{{1*/
    563 void PentaVertexInput::GetNodalFunctionsMINIDerivatives(double* dh1dh7,double* xyz_list, double* gauss_coord){
    564 
    565         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    566          * actual coordinate system: */
    567 
    568         int i;
    569 
    570         const  int numgrids=7;
    571         double dh1dh7_ref[3][numgrids];
    572         double Jinv[3][3];
    573 
    574 
    575         /*Get derivative values with respect to parametric coordinate system: */
    576         GetNodalFunctionsMINIDerivativesReference(&dh1dh7_ref[0][0], gauss_coord);
    577 
    578         /*Get Jacobian invert: */
    579         GetJacobianInvert(&Jinv[0][0], xyz_list, gauss_coord);
    580 
    581         /*Build dh1dh6:
    582          *
    583          * [dhi/dx]= Jinv'*[dhi/dr]
    584          * [dhi/dy]        [dhi/ds]
    585          * [dhi/dz]        [dhi/dzeta]
    586          */
    587 
    588         for (i=0;i<numgrids;i++){
    589                 *(dh1dh7+numgrids*0+i)=Jinv[0][0]*dh1dh7_ref[0][i]+Jinv[0][1]*dh1dh7_ref[1][i]+Jinv[0][2]*dh1dh7_ref[2][i];
    590                 *(dh1dh7+numgrids*1+i)=Jinv[1][0]*dh1dh7_ref[0][i]+Jinv[1][1]*dh1dh7_ref[1][i]+Jinv[1][2]*dh1dh7_ref[2][i];
    591                 *(dh1dh7+numgrids*2+i)=Jinv[2][0]*dh1dh7_ref[0][i]+Jinv[2][1]*dh1dh7_ref[1][i]+Jinv[2][2]*dh1dh7_ref[2][i];
    592         }
    593 
    594 }
    595 /*}}}*/
    596 /*FUNCTION PentaVertexInput::GetNodalFunctionsP1DerivativesReference {{{1*/
    597 void PentaVertexInput::GetNodalFunctionsP1DerivativesReference(double* dl1dl6,double* gauss_coord){
    598 
    599         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    600          * natural coordinate system) at the gaussian point. Those values vary along xi,eta,z */
    601 
    602         const int numgrids=6;
    603         double A1,A2,A3,z;
    604 
    605         A1=gauss_coord[0]; //first area coordinate value. In term of xi and eta: A1=(1-xi)/2-eta/(2*SQRT3);
    606         A2=gauss_coord[1]; //second area coordinate value In term of xi and eta: A2=(1+xi)/2-eta/(2*SQRT3);
    607         A3=gauss_coord[2]; //third area coordinate value  In term of xi and eta: A3=y/SQRT3;
    608         z=gauss_coord[3]; //fourth vertical coordinate value. Corresponding nodal function: (1-z)/2 and (1+z)/2
    609 
    610 
    611         /*First nodal function derivatives. The corresponding nodal function is N=A1*(1-z)/2. Its derivatives follow*/
    612         *(dl1dl6+numgrids*0+0)=-0.5*(1.0-z)/2.0;
    613         *(dl1dl6+numgrids*1+0)=-0.5/SQRT3*(1.0-z)/2.0;
    614         *(dl1dl6+numgrids*2+0)=-0.5*A1;
    615 
    616         /*Second nodal function: The corresponding nodal function is N=A2*(1-z)/2. Its derivatives follow*/
    617         *(dl1dl6+numgrids*0+1)=0.5*(1.0-z)/2.0;
    618         *(dl1dl6+numgrids*1+1)=-0.5/SQRT3*(1.0-z)/2.0;
    619         *(dl1dl6+numgrids*2+1)=-0.5*A2;
    620 
    621         /*Third nodal function: The corresponding nodal function is N=A3*(1-z)/2. Its derivatives follow*/
    622         *(dl1dl6+numgrids*0+2)=0.0;
    623         *(dl1dl6+numgrids*1+2)=1.0/SQRT3*(1.0-z)/2.0;
    624         *(dl1dl6+numgrids*2+2)=-0.5*A3;
    625 
    626         /*Fourth nodal function: The corresponding nodal function is N=A1*(1+z)/2. Its derivatives follow*/
    627         *(dl1dl6+numgrids*0+3)=-0.5*(1.0+z)/2.0;
    628         *(dl1dl6+numgrids*1+3)=-0.5/SQRT3*(1.0+z)/2.0;
    629         *(dl1dl6+numgrids*2+3)=0.5*A1;
    630 
    631         /*Fifth nodal function: The corresponding nodal function is N=A2*(1+z)/2. Its derivatives follow*/
    632         *(dl1dl6+numgrids*0+4)=0.5*(1.0+z)/2.0;
    633         *(dl1dl6+numgrids*1+4)=-0.5/SQRT3*(1.0+z)/2.0;
    634         *(dl1dl6+numgrids*2+4)=0.5*A2;
    635 
    636         /*Sixth nodal function: The corresponding nodal function is N=A3*(1+z)/2. Its derivatives follow*/
    637         *(dl1dl6+numgrids*0+5)=0.0;
    638         *(dl1dl6+numgrids*1+5)=1.0/SQRT3*(1.0+z)/2.0;
    639         *(dl1dl6+numgrids*2+5)=0.5*A3;
    640 }
    641 /*}}}*/
    642 /*FUNCTION PentaVertexInput::GetNodalFunctionsMINIDerivativesReference{{{1*/
    643 void PentaVertexInput::GetNodalFunctionsMINIDerivativesReference(double* dl1dl7,double* gauss_coord){
    644 
    645         /*This routine returns the values of the nodal functions derivatives  (with respect to the
    646          * natural coordinate system) at the gaussian point. */
    647 
    648         int    numgrids=7; //six plus bubble grids
    649 
    650         double r=gauss_coord[1]-gauss_coord[0];
    651         double s=-3.0/SQRT3*(gauss_coord[0]+gauss_coord[1]-2.0/3.0);
    652         double zeta=gauss_coord[3];
    653 
    654         /*First nodal function: */
    655         *(dl1dl7+numgrids*0+0)=-0.5*(1.0-zeta)/2.0;
    656         *(dl1dl7+numgrids*1+0)=-SQRT3/6.0*(1.0-zeta)/2.0;
    657         *(dl1dl7+numgrids*2+0)=-0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
    658 
    659         /*Second nodal function: */
    660         *(dl1dl7+numgrids*0+1)=0.5*(1.0-zeta)/2.0;
    661         *(dl1dl7+numgrids*1+1)=-SQRT3/6.0*(1.0-zeta)/2.0;
    662         *(dl1dl7+numgrids*2+1)=-0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
    663 
    664         /*Third nodal function: */
    665         *(dl1dl7+numgrids*0+2)=0;
    666         *(dl1dl7+numgrids*1+2)=SQRT3/3.0*(1.0-zeta)/2.0;
    667         *(dl1dl7+numgrids*2+2)=-0.5*(SQRT3/3.0*s+ONETHIRD);
    668 
    669         /*Fourth nodal function: */
    670         *(dl1dl7+numgrids*0+3)=-0.5*(1.0+zeta)/2.0;
    671         *(dl1dl7+numgrids*1+3)=-SQRT3/6.0*(1.0+zeta)/2.0;
    672         *(dl1dl7+numgrids*2+3)=0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
    673 
    674         /*Fith nodal function: */
    675         *(dl1dl7+numgrids*0+4)=0.5*(1.0+zeta)/2.0;
    676         *(dl1dl7+numgrids*1+4)=-SQRT3/6.0*(1.0+zeta)/2.0;
    677         *(dl1dl7+numgrids*2+4)=0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
    678 
    679         /*Sixth nodal function: */
    680         *(dl1dl7+numgrids*0+5)=0;
    681         *(dl1dl7+numgrids*1+5)=SQRT3/3.0*(1.0+zeta)/2.0;
    682         *(dl1dl7+numgrids*2+5)=0.5*(SQRT3/3.0*s+ONETHIRD);
    683 
    684         /*Seventh nodal function: */
    685         *(dl1dl7+numgrids*0+6)=9.0/2.0*r*(1.0+zeta)*(zeta-1.0)*(SQRT3*s+1.0);
    686         *(dl1dl7+numgrids*1+6)=9.0/4.0*(1+zeta)*(1-zeta)*(SQRT3*pow(s,2.0)-2.0*s-SQRT3*pow(r,2.0));
    687         *(dl1dl7+numgrids*2+6)=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(-2.0*zeta);
    688 
    689 }
    690 /*}}}*/
    691 /*FUNCTION PentaVertexInput::GetJacobian {{{1*/
    692 void PentaVertexInput::GetJacobian(double* J, double* xyz_list,double* gauss_coord){
    693 
    694         const int NDOF3=3;
    695         int i,j;
    696 
    697         /*The Jacobian is constant over the element, discard the gaussian points.
    698          * J is assumed to have been allocated of size NDOF2xNDOF2.*/
    699 
    700         double A1,A2,A3; //area coordinates
    701         double xi,eta,zi; //parametric coordinates
    702 
    703         double x1,x2,x3,x4,x5,x6;
    704         double y1,y2,y3,y4,y5,y6;
    705         double z1,z2,z3,z4,z5,z6;
    706 
    707         /*Figure out xi,eta and zi (parametric coordinates), for this gaussian point: */
    708         A1=gauss_coord[0];
    709         A2=gauss_coord[1];
    710         A3=gauss_coord[2];
    711 
    712         xi=A2-A1;
    713         eta=SQRT3*A3;
    714         zi=gauss_coord[3];
    715 
    716         x1=*(xyz_list+3*0+0);
    717         x2=*(xyz_list+3*1+0);
    718         x3=*(xyz_list+3*2+0);
    719         x4=*(xyz_list+3*3+0);
    720         x5=*(xyz_list+3*4+0);
    721         x6=*(xyz_list+3*5+0);
    722 
    723         y1=*(xyz_list+3*0+1);
    724         y2=*(xyz_list+3*1+1);
    725         y3=*(xyz_list+3*2+1);
    726         y4=*(xyz_list+3*3+1);
    727         y5=*(xyz_list+3*4+1);
    728         y6=*(xyz_list+3*5+1);
    729 
    730         z1=*(xyz_list+3*0+2);
    731         z2=*(xyz_list+3*1+2);
    732         z3=*(xyz_list+3*2+2);
    733         z4=*(xyz_list+3*3+2);
    734         z5=*(xyz_list+3*4+2);
    735         z6=*(xyz_list+3*5+2);
    736 
    737         *(J+NDOF3*0+0)=0.25*(x1-x2-x4+x5)*zi+0.25*(-x1+x2-x4+x5);
    738         *(J+NDOF3*1+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*zi+SQRT3/12.0*(-x1-x2+2*x3-x4-x5+2*x6);
    739         *(J+NDOF3*2+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*eta+1/4*(x1-x2-x4+x5)*xi +0.25*(-x1+x5-x2+x4);
    740 
    741         *(J+NDOF3*0+1)=0.25*(y1-y2-y4+y5)*zi+0.25*(-y1+y2-y4+y5);
    742         *(J+NDOF3*1+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*zi+SQRT3/12.0*(-y1-y2+2*y3-y4-y5+2*y6);
    743         *(J+NDOF3*2+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*eta+0.25*(y1-y2-y4+y5)*xi+0.25*(y4-y1+y5-y2);
    744 
    745         *(J+NDOF3*0+2)=0.25*(z1-z2-z4+z5)*zi+0.25*(-z1+z2-z4+z5);
    746         *(J+NDOF3*1+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*zi+SQRT3/12.0*(-z1-z2+2*z3-z4-z5+2*z6);
    747         *(J+NDOF3*2+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*eta+0.25*(z1-z2-z4+z5)*xi+0.25*(-z1+z5-z2+z4);
    748 
    749 }
    750 /*}}}*/
    751 /*FUNCTION PentaVertexInput::GetJacobianInvert {{{1*/
    752 void PentaVertexInput::GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss_coord){
    753 
    754         double Jdet;
    755         const int NDOF3=3;
    756 
    757         /*Call Jacobian routine to get the jacobian:*/
    758         GetJacobian(Jinv, xyz_list, gauss_coord);
    759 
    760         /*Invert Jacobian matrix: */
    761         MatrixInverse(Jinv,NDOF3,NDOF3,NULL,0,&Jdet);
    762 }
    763 /*}}}*/
    764 /*FUNCTION PentaVertexInput::GetBPattyn {{{1*/
    765 void PentaVertexInput::GetBPattyn(double* B, double* xyz_list, double* gauss_coord){
    766         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2.
    767          * For grid i, Bi can be expressed in the actual coordinate system
    768          * by:
    769          *       Bi=[ dh/dx          0      ]
    770          *          [   0           dh/dy   ]
    771          *          [ 1/2*dh/dy  1/2*dh/dx  ]
    772          *          [ 1/2*dh/dz      0      ]
    773          *          [  0         1/2*dh/dz  ]
    774          * where h is the interpolation function for grid i.
    775          *
    776          * We assume B has been allocated already, of size: 5x(NDOF2*numgrids)
    777          */
    778 
    779         int i;
    780         const int numgrids=6;
    781         const int NDOF3=3;
    782         const int NDOF2=2;
    783 
    784         double dh1dh6[NDOF3][numgrids];
    785 
    786         /*Get dh1dh6 in actual coordinate system: */
    787         GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss_coord);
    788 
    789         /*Build B: */
    790         for (i=0;i<numgrids;i++){
    791                 *(B+NDOF2*numgrids*0+NDOF2*i)=dh1dh6[0][i];
    792                 *(B+NDOF2*numgrids*0+NDOF2*i+1)=0.0;
    793 
    794                 *(B+NDOF2*numgrids*1+NDOF2*i)=0.0;
    795                 *(B+NDOF2*numgrids*1+NDOF2*i+1)=dh1dh6[1][i];
    796 
    797                 *(B+NDOF2*numgrids*2+NDOF2*i)=(float).5*dh1dh6[1][i];
    798                 *(B+NDOF2*numgrids*2+NDOF2*i+1)=(float).5*dh1dh6[0][i];
    799 
    800                 *(B+NDOF2*numgrids*3+NDOF2*i)=(float).5*dh1dh6[2][i];
    801                 *(B+NDOF2*numgrids*3+NDOF2*i+1)=0.0;
    802 
    803                 *(B+NDOF2*numgrids*4+NDOF2*i)=0.0;
    804                 *(B+NDOF2*numgrids*4+NDOF2*i+1)=(float).5*dh1dh6[2][i];
    805         }
    806 
    807 }
    808 /*}}}*/
    809 /*FUNCTION PentaVertexInput::GetBStokes {{{1*/
    810 void PentaVertexInput::GetBStokes(double* B, double* xyz_list, double* gauss_coord){
    811 
    812         /*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 3*DOFPERGRID.
    813          * For grid i, Bi can be expressed in the actual coordinate system
    814          * by:          Bi=[ dh/dx          0             0       0  ]
    815          *                                      [   0           dh/dy           0       0  ]
    816          *                                      [   0             0           dh/dy     0  ]
    817          *                                      [ 1/2*dh/dy    1/2*dh/dx        0       0  ]
    818          *                                      [ 1/2*dh/dz       0         1/2*dh/dx   0  ]
    819          *                                      [   0          1/2*dh/dz    1/2*dh/dy   0  ]
    820          *                                      [   0             0             0       h  ]
    821          *                                      [ dh/dx         dh/dy         dh/dz     0  ]
    822          *      where h is the interpolation function for grid i.
    823          *      Same thing for Bb except the last column that does not exist.
    824          */
    825 
    826         int i;
    827         const int calculationdof=3;
    828         const int numgrids=6;
    829         int DOFPERGRID=4;
    830 
    831         double dh1dh7[calculationdof][numgrids+1];
    832         double l1l6[numgrids];
    833 
    834 
    835         /*Get dh1dh7 in actual coordinate system: */
    836         GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss_coord);
    837         GetNodalFunctionsP1(l1l6, gauss_coord);
    838 
    839         /*Build B: */
    840         for (i=0;i<numgrids+1;i++){
    841                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7[0][i]; //B[0][DOFPERGRID*i]=dh1dh6[0][i];
    842                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
    843                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
    844                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
    845                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7[1][i];
    846                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
    847                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
    848                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
    849                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7[2][i];
    850                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=(float).5*dh1dh7[1][i];
    851                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=(float).5*dh1dh7[0][i];
    852                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
    853                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=(float).5*dh1dh7[2][i];
    854                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
    855                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=(float).5*dh1dh7[0][i];
    856                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
    857                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=(float).5*dh1dh7[2][i];
    858                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=(float).5*dh1dh7[1][i];
    859                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=0;
    860                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=0;
    861                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=0;
    862                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=dh1dh7[0][i];
    863                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=dh1dh7[1][i];
    864                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=dh1dh7[2][i];
    865         }
    866 
    867         for (i=0;i<numgrids;i++){ //last column not for the bubble function
    868                 *(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
    869                 *(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
    870                 *(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
    871                 *(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
    872                 *(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
    873                 *(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
    874                 *(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=l1l6[i];
    875                 *(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=0;
    876         }
    877 
    878 }
    879 /*}}}*/
    880483/*FUNCTION PentaVertexInput::SquareMin{{{1*/
    881484void PentaVertexInput::SquareMin(double* psquaremin, bool process_units,Parameters* parameters){
  • issm/trunk/src/c/objects/Inputs/PentaVertexInput.h

    r4882 r4885  
    6464                void GetVyStrainRate3dPattyn(double* epsilonvy,double* xyz_list, double* gauss);
    6565                void ChangeEnum(int newenumtype);
    66                 void GetNodalFunctionsP1(double* l1l6, double* gauss_coord);
    67                 void GetNodalFunctionsMINI(double* l1l7, double* gauss_coord);
    68                 void GetNodalFunctionsP1Derivatives(double* dh1dh6,double* xyz_list, double* gauss_coord);
    69                 void GetNodalFunctionsMINIDerivatives(double* dh1dh7,double* xyz_list, double* gauss_coord);
    70                 void GetNodalFunctionsP1DerivativesReference(double* dl1dl6,double* gauss_coord);
    71                 void GetNodalFunctionsMINIDerivativesReference(double* dl1dl7,double* gauss_coord);
    72                 void GetJacobian(double* J, double* xyz_list,double* gauss_coord);
    73                 void GetJacobianInvert(double*  Jinv, double* xyz_list,double* gauss_coord);
    74                 void GetBPattyn(double* B, double* xyz_list, double* gauss_coord);
    75                 void GetBStokes(double* B, double* xyz_list, double* gauss_coord);
     66
    7667                void SquareMin(double* psquaremin, bool process_units,Parameters* parameters);
    7768                void Scale(double scale_factor);
  • issm/trunk/src/c/objects/Inputs/TriaVertexInput.cpp

    r4769 r4885  
    271271
    272272        /*Get B matrix: */
    273         GetB(&B[0][0], xyz_list, gauss);
     273        GetBMacAyeal(&B[0][0], xyz_list, gauss);
    274274
    275275        /*Here, we are computing the strain rate of (vx,0)*/
     
    295295
    296296        /*Get B matrix: */
    297         GetB(&B[0][0], xyz_list, gauss);
     297        GetBMacAyeal(&B[0][0], xyz_list, gauss);
    298298
    299299        /*Here, we are computing the strain rate of (0,vy)*/
  • issm/trunk/src/c/shared/Matrix/MatrixUtils.cpp

    r3775 r4885  
    33 */
    44
    5 /*
    6 
    7         TripleMultiply    Perform triple matrix product a*b*c+d.
    8 
    9 
    10         Input:
    11                 double*    a        first matrix
    12                 int        nrowa    number of rows in a
    13                 int        ncola    number of columns in a
    14                 int        itrna    transpose flag for a
    15                 double*    b        second matrix
    16                 int        nrowb    number of rows in b
    17                 int        ncolb    number of columns in b
    18                 int        itrnb    transpose flag for b
    19                 double*    c        third matrix
    20                 int        nrowc    number of rows in c
    21                 int        ncolc    number of columns in c
    22                 int        itrnc    transpose flag for c
    23                 double*    d        addition matrix
    24                 int        iaddd    addition flag for d
    25 
    26         Output:
    27                 double*    d        product matrix
    28                 int                 function return value
    29 
    30 */
     5/*Headers*/
     6/*{{{1*/
    317#include "./matrix.h"
    328#include "../Exceptions/exceptions.h"
     
    3814#include <float.h>    /*  DBL_EPSILON  */
    3915#include "../../include/include.h"
    40 
     16/*}}}*/
     17
     18/*FUNCTION TripleMultiply {{{1*/
    4119int TripleMultiply( double* a, int nrowa, int ncola, int itrna, double* b, int nrowb, int ncolb, int itrnb, double* c, int nrowc, int ncolc, int itrnc, double* d, int iaddd){
     20        /*TripleMultiply    Perform triple matrix product a*b*c+d.*/
    4221       
    4322        int idima,idimb,idimc,idimd;
     
    11695                xfree((void **)&dtemp);
    11796        }
    118 }
    119 
    120 
    121 
    122 
    123 
    124 /*
    125 
    126         MatrixMultiply    Perform matrix multiplication a*b+c.
    127 
    128 
    129         Input:
    130                 double*    a        first matrix
    131                 int        nrowa    number of rows in a
    132                 int        ncola    number of columns in a
    133                 int        itrna    transpose flag for a
    134                 double*    b        second matrix
    135                 int        nrowb    number of rows in b
    136                 int        ncolb    number of columns in b
    137                 int        itrnb    transpose flag for b
    138                 double*    c        addition matrix
    139                 int        iaddc    addition flag for c
    140 
    141         Output:
    142                 double*    c        product matrix
    143                 int                 function return value
    144 
    145 */
    146 
    147 int MatrixMultiply( double* a,
    148                                     int nrowa,
    149                                     int ncola,
    150                                     int itrna,
    151                                     double* b,
    152                                     int nrowb,
    153                                     int ncolb,
    154                                     int itrnb,
    155                                     double* c,
    156                                     int iaddc )
    157 {
     97}/*}}}*/
     98/*FUNCTION MatrixMuliply {{{1*/
     99int MatrixMultiply( double* a, int nrowa, int ncola, int itrna, double* b, int nrowb, int ncolb, int itrnb, double* c, int iaddc ){
     100        /*MatrixMultiply    Perform matrix multiplication a*b+c.*/
    158101        int noerr=1;
    159102        int i,j,k,ipta,iptb,iptc;
     
    161104
    162105/*  set up dimensions and increments for matrix a  */
    163 
    164106        if (!itrna) {
    165107                nrowc=nrowa;
     
    168110                jinca=1;
    169111        }
    170 
    171112        else {
    172113                nrowc=ncola;
     
    177118
    178119/*  set up dimensions and increments for matrix b  */
    179 
    180120        if (!itrnb) {
    181121                ncolc=ncolb;
     
    184124                jincb=1;
    185125        }
    186 
    187126        else {
    188127                ncolc=nrowb;
     
    225164
    226165        return noerr;
    227 }
    228 
    229 
    230 /*
    231 
    232         MatrixInverse    Perform matrix inversion and linear equation solution.
    233 
    234 
    235         Input:
    236                 double*    a        coefficient matrix [ndim][ndim]
    237                 int        ndim     row and column dimension of a
    238                 int        nrow     number of rows in a
    239                 double*    b        right-hand vectors [ndim][nvec] (may be nULL)
    240                 int        nvec     number of vectors in b (0 for NULL b)
    241 
    242         Output:
    243                 double*    a        inverted matrix [ndim][ndim]
    244                 double*    b        solution vectors [ndim][nvec] (may be NULL)
    245                 double*    pdet     determinant (may be NULL)
    246                 int                 error flag
     166}/*}}}*/
     167/*FUNCTION MatrixInverse {{{1*/
     168int MatrixInverse( double* a, int ndim, int nrow, double* b, int nvec, double* pdet ){
     169/* MatrixInverse    Perform matrix inversion and linear equation solution.
    247170
    248171        This function uses Gaussian elimination on the original matrix
     
    253176
    254177        Gaussian elimination is inherently inefficient, and so this is
    255         intended for small matrices.
    256 
    257 */
    258 
    259 int MatrixInverse( double* a,
    260                                int ndim,
    261                                int nrow,
    262                                double* b,
    263                                int nvec,
    264                                double* pdet )
    265 {
     178        intended for small matrices.  */
    266179        int noerr=1;
    267180        int i,j,k,ipt,jpt,irow,icol,ipiv,ncol;
     
    424337
    425338        return noerr;
    426 }
     339}/*}}}*/
Note: See TracChangeset for help on using the changeset viewer.