Changeset 4885


Ignore:
Timestamp:
Jul 29, 2010, 2:40:49 PM (16 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.