Index: /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateConstraintsDiagnosticStokes.cpp
===================================================================
--- /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateConstraintsDiagnosticStokes.cpp	(revision 393)
+++ /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateConstraintsDiagnosticStokes.cpp	(revision 394)
@@ -91,5 +91,5 @@
 	/*Free data: */
 	xfree((void**)&gridonstokes);
-	
+
 	/*Assign output pointer: */
 	*pconstraints=constraints;
Index: /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateElementsNodesAndMaterialsDiagnosticStokes.cpp
===================================================================
--- /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateElementsNodesAndMaterialsDiagnosticStokes.cpp	(revision 393)
+++ /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateElementsNodesAndMaterialsDiagnosticStokes.cpp	(revision 394)
@@ -514,5 +514,5 @@
 	xfree((void**)&model->gridonstokes);
 	xfree((void**)&model->borderstokes);
-		
+
 	cleanup_and_return:
 
Index: /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateLoadsDiagnosticStokes.cpp
===================================================================
--- /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateLoadsDiagnosticStokes.cpp	(revision 393)
+++ /issm/trunk/src/c/ModelProcessorx/DiagnosticStokes/CreateLoadsDiagnosticStokes.cpp	(revision 394)
@@ -51,4 +51,5 @@
 	int numberofsegs_diag_stokes;
 	int count;
+
 
 	/*Create loads: */
@@ -134,15 +135,16 @@
 	#endif
 
-		if ((model->gridonbed[i]) && (model->gridonicesheet[i]) && (model->gridonstokes[i]))
+		if ((model->gridonbed[i]) && (model->gridonicesheet[i]) && (model->gridonstokes[i])){
 
-		pengrid_id=count+1; //matlab indexing
-		pengrid_node_id=i+1;
-		pengrid_dof=1;
-		pengrid_penalty_offset=model->penalty_offset;
+			pengrid_id=count+1; //matlab indexing
+			pengrid_node_id=i+1;
+			pengrid_dof=1;
+			pengrid_penalty_offset=model->penalty_offset;
 
-		pengrid= new Pengrid(pengrid_id, pengrid_node_id,pengrid_dof, pengrid_active, pengrid_penalty_offset,pengrid_thermal_steadystate);
-		
-		loads->AddObject(icefront);
-		count++;
+			pengrid= new Pengrid(pengrid_id, pengrid_node_id,pengrid_dof, pengrid_active, pengrid_penalty_offset,pengrid_thermal_steadystate);
+			
+			loads->AddObject(icefront);
+			count++;
+		}
 	#ifdef _PARALLEL_
 	} //if((model->my_grids[i]==1))
Index: /issm/trunk/src/c/ModelProcessorx/Model.cpp
===================================================================
--- /issm/trunk/src/c/ModelProcessorx/Model.cpp	(revision 393)
+++ /issm/trunk/src/c/ModelProcessorx/Model.cpp	(revision 394)
@@ -307,4 +307,5 @@
 	ModelFetchData((void**)&model->ishutter,NULL,NULL,model_handle,"ishutter","Integer",NULL);
 	ModelFetchData((void**)&model->ismacayealpattyn,NULL,NULL,model_handle,"ismacayealpattyn","Integer",NULL);
+	ModelFetchData((void**)&model->isstokes,NULL,NULL,model_handle,"isstokes","Integer",NULL);
 
 	/*!Get drag_type, drag and p,q: */
Index: /issm/trunk/src/c/objects/Friction.cpp
===================================================================
--- /issm/trunk/src/c/objects/Friction.cpp	(revision 393)
+++ /issm/trunk/src/c/objects/Friction.cpp	(revision 394)
@@ -35,4 +35,5 @@
 	friction->p=UNDEF;
 	friction->q=UNDEF;
+	friction->analysis_type=UNDEF;
 	
 	return 1;
Index: /issm/trunk/src/c/objects/Friction.h
===================================================================
--- /issm/trunk/src/c/objects/Friction.h	(revision 393)
+++ /issm/trunk/src/c/objects/Friction.h	(revision 394)
@@ -19,4 +19,5 @@
 	double  p;
 	double  q;
+	int     analysis_type;
 
 };
Index: /issm/trunk/src/c/objects/Matice.cpp
===================================================================
--- /issm/trunk/src/c/objects/Matice.cpp	(revision 393)
+++ /issm/trunk/src/c/objects/Matice.cpp	(revision 394)
@@ -306,4 +306,72 @@
 }
 
+#undef __FUNCT__ 
+#define __FUNCT__ "MatIce::GetViscosity3dStokes"
+void  Matice::GetViscosity3dStokes(double* pviscosity3d, double* epsilon){
+
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *                                 2*B
+	 * viscosity3d= -------------------------------------------------------------------
+	 *     2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 *     where mu is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	 *     vector, and n the flow law exponent.
+	 *
+	 * If epsilon is NULL, it means this is the first time Emg is being run, and we 
+	 * return g, initial viscosity.
+	 */
+	
+	/*output: */
+	double viscosity3d;
+
+	/*input strain rate: */
+	double exx,eyy,exy,exz,eyz,ezz;
+
+	/*Intermediary value A and exponent e: */
+	double A,e;
+	double eps0;
+
+	eps0=10^-27;
+	
+	if (n==1){
+		/*Viscous behaviour! viscosity3d=B: */
+		viscosity3d=B;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0) && (epsilon[5]==0)){
+			viscosity3d=pow(10,14);
+		}
+		else{
+
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			ezz=*(epsilon+2); //not used
+			exy=*(epsilon+3);
+			exz=*(epsilon+4);
+			eyz=*(epsilon+5);
+
+			/*Build viscosity: viscosity3d=2*B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+pow(exz,2)+pow(eyz,2)+exx*eyy+pow(eps0,2);
+			if(A==0){
+				/*Maxiviscosity3dm viscosity for 0 shear areas: */
+				viscosity3d=4.5*pow(10,17);
+			}
+			else{
+				e=(n-1)/2/n;
+			
+				viscosity3d=2*B/(2*pow(A,e));
+			}
+		}
+	}
+	#ifdef _DEBUG_
+	_printf_("Viscosity %lf\n",viscosity3d);
+	#endif
+
+	/*Assign output pointers:*/
+	*pviscosity3d=viscosity3d;
+}
 double Matice::GetB(){
 	return B;
Index: /issm/trunk/src/c/objects/Matice.h
===================================================================
--- /issm/trunk/src/c/objects/Matice.h	(revision 393)
+++ /issm/trunk/src/c/objects/Matice.h	(revision 394)
@@ -35,4 +35,5 @@
 		void  GetViscosity2(double* pviscosity2, double* pepsilon);
 		void  GetViscosity3d(double* pviscosity3d, double* pepsilon);
+		void  GetViscosity3dStokes(double* pviscosity3d, double* epsilon);
 		Object* copy();
 		double GetB();
Index: /issm/trunk/src/c/objects/Pengrid.cpp
===================================================================
--- /issm/trunk/src/c/objects/Pengrid.cpp	(revision 393)
+++ /issm/trunk/src/c/objects/Pengrid.cpp	(revision 394)
@@ -136,5 +136,5 @@
 	return my_rank; 
 }
-void  Pengrid::DistributeNumDofs(int* numdofspernode,int analysis_type){return;}
+void  Pengrid::DistributeNumDofs(int* numdofpernode,int analysis_type){return;}
 
 #undef __FUNCT__ 
@@ -181,7 +181,57 @@
 #define __FUNCT__ "Pengrid::PenaltyCreateKMatrix"
 void  Pengrid::PenaltyCreateKMatrix(Mat Kgg,void* inputs,double kmax,int analysis_type){
-	throw ErrorException(__FUNCT__," not implemented yet!");
-}
-		
+
+	if ((analysis_type==DiagnosticStokesAnalysisEnum())){
+
+		PenaltyCreateKMatrixDiagnosticStokes( Kgg,inputs,kmax,analysis_type);
+
+	}
+	else{
+		throw ErrorException(__FUNCT__,exprintf("%s%i%s\n","analysis: ",analysis_type," not supported yet"));
+	}
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Pengrid::PenaltyCreateKMatrixDiagnosticStokes"
+void  Pengrid::PenaltyCreateKMatrixDiagnosticStokes(Mat Kgg,void* vinputs,double kmax,int analysis_type){
+	
+	const int numgrids=1;
+	const int NDOF3=3;
+	const int numdof=numgrids*NDOF3;
+	int       doflist[numdof];
+	int       numberofdofspernode;
+
+	int dofs1=0;
+	int dofs2=1;
+	double slope[2];
+	int found=0;
+	double Ke[4][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}};
+	
+	ParameterInputs* inputs=NULL;
+	
+
+	/*recover pointers: */
+	inputs=(ParameterInputs*)vinputs;
+
+	/*Get dof list: */
+	GetDofList(&doflist[0],&numberofdofspernode);
+	
+	/*recover slope: */
+	found=inputs->Recover("bedslopex",&slope[0],1,&dofs1,numgrids,(void**)&node);
+	if(!found)throw ErrorException(__FUNCT__," bedslopex needed in inputs!");
+	found=inputs->Recover("bedslopey",&slope[1],1,&dofs2,numgrids,(void**)&node);
+	if(!found)throw ErrorException(__FUNCT__," bedslopey needed in inputs!");
+
+	//Create elementary matrix: add penalty to contrain wb (wb=ub*db/dx+vb*db/dy)
+	Ke[0][0]=-slope[0]*kmax*pow(10.0,penalty_offset);
+	Ke[1][1]=-slope[1]*kmax*pow(10.0,penalty_offset);
+	Ke[2][2]=kmax*pow(10,penalty_offset);
+	
+	
+	/*Add Ke to global matrix Kgg: */
+	MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke,ADD_VALUES);
+}
+
 #undef __FUNCT__ 
 #define __FUNCT__ "Pengrid::PenaltyCreatePVector"
@@ -194,2 +244,17 @@
 }
 
+
+void  Pengrid::GetDofList(int* doflist,int* pnumberofdofspernode){
+
+	int j;
+	int doflist_per_node[MAXDOFSPERNODE];
+	int numberofdofspernode;
+	
+	node->GetDofList(&doflist_per_node[0],&numberofdofspernode);
+	for(j=0;j<numberofdofspernode;j++){
+		doflist[j]=doflist_per_node[j];
+	}
+
+	/*Assign output pointers:*/
+	*pnumberofdofspernode=numberofdofspernode;
+}
Index: /issm/trunk/src/c/objects/Pengrid.h
===================================================================
--- /issm/trunk/src/c/objects/Pengrid.h	(revision 393)
+++ /issm/trunk/src/c/objects/Pengrid.h	(revision 394)
@@ -46,4 +46,6 @@
 		void  PenaltyCreateKMatrix(Mat Kgg,void* inputs,double kmax,int analysis_type);
 		void  PenaltyCreatePVector(Vec pg,void* inputs,double kmax,int analysis_type);
+		void  PenaltyCreateKMatrixDiagnosticStokes(Mat Kgg,void* inputs,double kmax,int analysis_type);
+		void  GetDofList(int* doflist,int* pnumberofdofspernode);
 		Object* copy();
 
Index: /issm/trunk/src/c/objects/Penta.cpp
===================================================================
--- /issm/trunk/src/c/objects/Penta.cpp	(revision 393)
+++ /issm/trunk/src/c/objects/Penta.cpp	(revision 394)
@@ -297,4 +297,9 @@
 
 	}
+	else if ((analysis_type==DiagnosticStokesAnalysisEnum())){
+
+		CreateKMatrixDiagnosticStokes( Kgg,inputs,analysis_type);
+
+	}
 	else if (
 			(analysis_type==SurfaceSlopeComputeXAnalysisEnum()) || 
@@ -323,7 +328,7 @@
 	/* node data: */
 	const int    numgrids=6;
-	const int    numdofs=2*numgrids;
+	const int    numdof=2*numgrids;
 	double       xyz_list[numgrids][3];
-	int          doflist[numdofs];
+	int          doflist[numdof];
 	int          numberofdofspernode;
 	
@@ -363,7 +368,7 @@
 
 	/* matrices: */
-	double B[5][numdofs];
-	double Bprime[5][numdofs];
-	double L[2][numdofs];
+	double B[5][numdof];
+	double Bprime[5][numdof];
+	double L[2][numdof];
 	double D[5][5]={{ 0,0,0,0,0 },{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}};              // material matrix, simple scalar matrix.
 	double D_scalar;
@@ -372,7 +377,7 @@
 
 	/* local element matrices: */
-	double Ke_gg[numdofs][numdofs]; //local element stiffness matrix 
-	double Ke_gg_gaussian[numdofs][numdofs]; //stiffness matrix evaluated at the gaussian point.
-	double Ke_gg_drag_gaussian[numdofs][numdofs]; //stiffness matrix contribution from drag
+	double Ke_gg[numdof][numdof]; //local element stiffness matrix 
+	double Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
+	double Ke_gg_drag_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
 	double Jdet;
 	
@@ -433,6 +438,6 @@
 
 		/* Set Ke_gg to 0: */
-		for(i=0;i<numdofs;i++){
-			for(j=0;j<numdofs;j++){
+		for(i=0;i<numdof;i++){
+			for(j=0;j<numdof;j++){
 				Ke_gg[i][j]=0.0;
 			}
@@ -521,12 +526,12 @@
 		
 				/*  Do the triple product tB*D*Bprime: */
-				TripleMultiply( &B[0][0],5,numdofs,1,
+				TripleMultiply( &B[0][0],5,numdof,1,
 						&D[0][0],5,5,0,
-						&Bprime[0][0],5,numdofs,0,
+						&Bprime[0][0],5,numdof,0,
 						&Ke_gg_gaussian[0][0],0);
 
 				/* Add the Ke_gg_gaussian, and optionally Ke_gg_gaussian onto Ke_gg: */
-				for( i=0; i<numdofs; i++){
-					for(j=0;j<numdofs;j++){
+				for( i=0; i<numdof; i++){
+					for(j=0;j<numdof;j++){
 						Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
 					}
@@ -537,5 +542,5 @@
 
 		/*Add Ke_gg to global matrix Kgg: */
-		MatSetValues(Kgg,numdofs,doflist,numdofs,doflist,(const double*)Ke_gg,ADD_VALUES);
+		MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
 	
 		//Deal with 2d friction at the bedrock interface
@@ -576,7 +581,7 @@
 	const int    numgrids=6;
 	const int    NDOF1=1;
-	const int    numdofs=NDOF1*numgrids;
+	const int    numdof=NDOF1*numgrids;
 	double       xyz_list[numgrids][3];
-	int          doflist[numdofs];
+	int          doflist[numdof];
 	int          numberofdofspernode;
 
@@ -598,6 +603,6 @@
 
 	/* matrices: */
-	double  Ke_gg[numdofs][numdofs];
-	double  Ke_gg_gaussian[numdofs][numdofs];
+	double  Ke_gg[numdof][numdof];
+	double  Ke_gg_gaussian[numdof][numdof];
 	double  Jdet;
 	double  B[NDOF1][numgrids];
@@ -629,6 +634,6 @@
 
 	/* Set Ke_gg to 0: */
-	for(i=0;i<numdofs;i++){
-		for(j=0;j<numdofs;j++){
+	for(i=0;i<numdof;i++){
+		for(j=0;j<numdof;j++){
 			Ke_gg[i][j]=0.0;
 		}
@@ -684,6 +689,6 @@
 
 			/* Add the Ke_gg_gaussian, and optionally Ke_gg_drag_gaussian onto Ke_gg: */
-			for( i=0; i<numdofs; i++){
-				for(j=0;j<numdofs;j++){
+			for( i=0; i<numdof; i++){
+				for(j=0;j<numdof;j++){
 					Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
 				}
@@ -693,5 +698,5 @@
 
 	/*Add Ke_gg to global matrix Kgg: */
-	MatSetValues(Kgg,numdofs,doflist,numdofs,doflist,(const double*)Ke_gg,ADD_VALUES);
+	MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)Ke_gg,ADD_VALUES);
 	
 	cleanup_and_return: 
@@ -705,4 +710,293 @@
 
 #undef __FUNCT__ 
+#define __FUNCT__ "Penta:CreateKMatrixDiagnosticStokes"
+void Penta::CreateKMatrixDiagnosticStokes( Mat Kgg, void* vinputs, int analysis_type){
+
+	int i,j;
+
+	int numgrids=6;
+	int DOFPERGRID=4;
+	int numdof=numgrids*DOFPERGRID;
+	int doflist[numdof];
+	int numberofdofspernode;
+
+	int numgrids2d=3;
+	int numdof2d=numgrids2d*DOFPERGRID;
+
+	int   dofs[3]={0,1,2};
+
+	double K_terms[numdof][numdof];
+
+	/*Material properties: */
+	double         gravity,rho_ice,rho_water;
+
+	
+	/*Collapsed formulation: */
+	Tria*  tria=NULL;
+
+	/*Grid data: */
+	double        xyz_list[numgrids][3];
+	
+	/*parameters: */
+	double		   xyz_list_tria[numgrids2d][3];
+	double		   surface_normal[3];
+	double		   bed_normal[3];
+	double         vxvyvz_list[numgrids][3];
+	double         thickness;
+
+	/*matrices: */
+	double     Ke_temp[27][27]; //for the six nodes and the bubble 
+	double     Ke_reduced[numdof][numdof]; //for the six nodes only
+	double     Ke_gaussian[27][27];
+	double     Ke_drag_gaussian[numdof2d][numdof2d];
+	double     B[8][27];
+	double     B_prime[8][27];
+	double     LStokes[14][numdof2d];
+	double     LprimeStokes[14][numdof2d];
+	double     Jdet;
+	double     Jdet2d;
+	double     D[8][8]={{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 }};          
+	double     D_scalar;
+	double     tBD[numdof][8];
+	double     DLStokes[14][14];
+	double     tLDStokes[numdof2d][14];
+	
+	/* gaussian points: */
+	int     num_area_gauss;
+	int     igarea,igvert;
+	double* first_gauss_area_coord  =  NULL;
+	double* second_gauss_area_coord =  NULL;
+	double* third_gauss_area_coord  =  NULL;
+	double* vert_gauss_coord = NULL;
+	double* area_gauss_weights  =  NULL;
+	double* vert_gauss_weights  =  NULL;
+
+	/* specific gaussian point: */
+	double  gauss_weight,area_gauss_weight,vert_gauss_weight;
+	double  gauss_coord[4];
+	double  gauss_coord_tria[3];
+	int area_order=5;
+	int	num_vert_gauss=5;
+
+	double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double  viscosity;
+	double  alpha2_list[numgrids2d];
+	double  alpha2_gauss;
+	
+	ParameterInputs* inputs=NULL;
+
+	/*recover pointers: */
+	inputs=(ParameterInputs*)vinputs;
+
+	/* Set K_terms  to 0: */
+	for(i=0;i<numdof;i++){
+		for(j=0;j<numdof;j++){
+			K_terms[i][j]=0.0;
+		}
+	}
+	
+	/*recovre material parameters: */
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+
+
+	/* Get node coordinates and dof list: */
+	GetElementNodeData( &xyz_list[0][0], nodes, numgrids);
+	GetDofList(&doflist[0],&numberofdofspernode);
+
+	/*recover extra inputs from users, at current convergence iteration: */
+	inputs->Recover("velocity",&vxvyvz_list[0][0],3,dofs,numgrids,(void**)nodes);
+
+	/*Initialize Ke_temp to zero befor adding terms */
+	for (i=0;i<27;i++){
+		for (j=0;j<27;j++){
+			Ke_temp[i][j]=0;
+		}
+	}
+
+	/* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore 
+	   get tria gaussian points as well as segment gaussian points. For tria gaussian 
+	   points, order of integration is 2, because we need to integrate the product tB*D*B' 
+	   which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian 
+	   points, same deal, which yields 3 gaussian points.*/
+
+
+	area_order=5;
+	num_vert_gauss=5;
+
+	/* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
+	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);
+
+	/* Start  looping on the number of gaussian points: */
+	for (igarea=0; igarea<num_area_gauss; igarea++){
+		for (igvert=0; igvert<num_vert_gauss; igvert++){
+			/*Pick up the gaussian point: */
+			area_gauss_weight=*(area_gauss_weights+igarea);
+			vert_gauss_weight=*(vert_gauss_weights+igvert);
+			gauss_weight=area_gauss_weight*vert_gauss_weight;
+			gauss_coord[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord[2]=*(third_gauss_area_coord+igarea);
+			gauss_coord[3]=*(vert_gauss_coord+igvert);
+
+
+			/*Compute thickness: */
+			GetParameterValue(&thickness, &h[0],gauss_coord);
+
+			/*Compute strain rate: */
+			GetStrainRateStokes(&epsilon[0],&vxvyvz_list[0][0],&xyz_list[0][0],gauss_coord);
+		
+			/*Get viscosity: */
+			matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+			/*Get B and Bprime matrices: */
+			GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord); 
+			GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord); 
+
+			/* Get Jacobian determinant: */
+			GetJacobianDeterminant(&Jdet, &xyz_list[0][0],&gauss_coord[0]);
+
+			/* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant 
+			 * onto this scalar matrix, so that we win some computational time: */
+			D_scalar=gauss_weight*Jdet;
+			for (i=0;i<6;i++){
+				D[i][i]=D_scalar*viscosity;
+			}
+			for (i=6;i<8;i++){
+				D[i][i]=-D_scalar*stokesreconditioning;
+			}
+
+
+			/*  Do the triple product tB*D*Bprime: */
+			MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
+			MatrixMultiply(&tBD[0][0],27,8,0,&B_prime[0][0],8,27,0,&Ke_gaussian[0][0],0);
+
+			/*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
+			for(i=0;i<27;i++){
+				for(j=0;j<27;j++){
+					Ke_temp[i][j]+=Ke_gaussian[i][j];
+				}
+			}
+		}
+	}
+
+	if((onbed==1) && (shelf==0)){
+
+
+		/*Build alpha2_list used by drag stiffness matrix*/
+		Friction* friction=NewFriction();
+		
+		/*Initialize all fields: */
+		friction->element_type=(char*)xmalloc((strlen("2d")+1)*sizeof(char));
+		strcpy(friction->element_type,"2d");
+		
+		friction->gravity=matpar->GetG();
+		friction->rho_ice=matpar->GetRhoIce();
+		friction->rho_water=matpar->GetRhoWater();
+		friction->K=&k[0];
+		friction->bed=&b[0];
+		friction->thickness=&h[0];
+		friction->velocities=&vxvyvz_list[0][0];
+		friction->p=p;
+		friction->q=q;
+		friction->analysis_type=analysis_type;
+
+		/*Compute alpha2_list: */
+		FrictionGetAlpha2(&alpha2_list[0],friction);
+
+		/*Erase friction object: */
+		DeleteFriction(&friction);
+
+		for(i=0;i<numgrids2d;i++){
+			for(j=0;j<3;j++){
+				xyz_list_tria[i][j]=xyz_list[i][j];
+			}
+		}
+		
+		
+		GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
+
+		/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+		for (igarea=0; igarea<num_area_gauss; igarea++){
+			gauss_weight=*(area_gauss_weights+igarea);
+			gauss_coord[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord[2]=*(third_gauss_area_coord+igarea);
+			gauss_coord[3]=-1;
+			
+			gauss_coord_tria[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
+	
+			/*Get the Jacobian determinant */
+			tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
+			
+			/*Get L matrix if viscous basal drag present: */
+			GetLStokes(&LStokes[0][0],  gauss_coord_tria);
+			GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss_coord_tria, gauss_coord);
+				
+			/*Compute strain rate: */
+			GetStrainRateStokes(&epsilon[0],&vxvyvz_list[0][0],&xyz_list[0][0],gauss_coord);
+		
+			/*Get viscosity at last iteration: */
+			matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+	
+			/*Get normal vecyor to the bed */
+			SurfaceNormal(&surface_normal[0],xyz_list_tria);
+			
+			bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
+			bed_normal[1]=-surface_normal[1];
+			bed_normal[2]=-surface_normal[2];
+
+			/*Calculate DL on gauss point */
+			tria->GetParameterValue(&alpha2_gauss,&alpha2_list[0],gauss_coord_tria);
+
+			DLStokes[0][0]=alpha2_gauss*gauss_weight*Jdet2d;
+			DLStokes[1][1]=alpha2_gauss*gauss_weight*Jdet2d;
+			DLStokes[2][2]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
+			DLStokes[3][3]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
+			DLStokes[4][4]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[0]*bed_normal[2];
+			DLStokes[5][5]=-alpha2_gauss*gauss_weight*Jdet2d*bed_normal[1]*bed_normal[2];
+			DLStokes[6][6]=-viscosity*gauss_weight*Jdet2d*bed_normal[0];
+			DLStokes[7][7]=-viscosity*gauss_weight*Jdet2d*bed_normal[1];
+			DLStokes[8][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[2];
+			DLStokes[9][8]=-viscosity*gauss_weight*Jdet2d*bed_normal[0]/2.0;
+			DLStokes[10][10]=-viscosity*gauss_weight*Jdet2d*bed_normal[1]/2.0;
+			DLStokes[11][11]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[0];
+			DLStokes[12][12]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[1];
+			DLStokes[13][13]=stokesreconditioning*gauss_weight*Jdet2d*bed_normal[2];
+
+			/*  Do the triple product tL*D*L: */
+			MatrixMultiply(&LStokes[0][0],14,numdof2d,1,&DLStokes[0][0],14,14,0,&tLDStokes[0][0],0);
+			MatrixMultiply(&tLDStokes[0][0],numdof2d,14,0,&LprimeStokes[0][0],14,numdof2d,0,&Ke_drag_gaussian[0][0],0);
+
+			for(i=0;i<numdof2d;i++){
+				for(j=0;j<numdof2d;j++){
+					K_terms[i][j]+=Ke_drag_gaussian[i][j];
+				}
+			}
+		}
+	} //if ( (onbed==1) && (shelf==0))
+	
+	/*Reduce the matrix */
+	ReduceMatrixStokes(&Ke_reduced[0][0], &Ke_temp[0][0]);
+
+	for(i=0;i<numdof;i++){
+		for(j=0;j<numdof;j++){
+			K_terms[i][j]+=Ke_reduced[i][j];
+		}
+	}
+
+	/*Add Ke_gg to global matrix Kgg: */
+	MatSetValues(Kgg,numdof,doflist,numdof,doflist,(const double*)K_terms,ADD_VALUES);
+	
+	cleanup_and_return: 
+
+
+	return;
+}
+
+#undef __FUNCT__ 
 #define __FUNCT__ "Penta::CreatePVector"
 void  Penta::CreatePVector(Vec pg, void* inputs, int analysis_type){
@@ -716,4 +1010,8 @@
 
 		CreatePVectorDiagnosticVert( pg,inputs,analysis_type);
+	}
+	else if ((analysis_type==DiagnosticStokesAnalysisEnum())){
+
+		CreatePVectorDiagnosticStokes( pg,inputs,analysis_type);
 	}
 	else if (
@@ -1344,7 +1642,7 @@
 	const int    numgrids=6;
 	const int    NDOF2=2;
-	const int    numdofs=NDOF2*numgrids;
+	const int    numdof=NDOF2*numgrids;
 	double       xyz_list[numgrids][3];
-	int          doflist[numdofs];
+	int          doflist[numdof];
 	int          numberofdofspernode;
 	
@@ -1377,6 +1675,6 @@
 
 	/*element vector at the gaussian points: */
-	double  pe_g[numdofs];
-	double  pe_g_gaussian[numdofs];
+	double  pe_g[numdof];
+	double  pe_g_gaussian[numdof];
 
 	ParameterInputs* inputs=NULL;
@@ -1416,5 +1714,5 @@
 
 		/* Set pe_g to 0: */
-		for(i=0;i<numdofs;i++) pe_g[i]=0.0;
+		for(i=0;i<numdof;i++) pe_g[i]=0.0;
 
 		/*Get gaussian points and weights :*/
@@ -1469,5 +1767,5 @@
 
 				/*Add pe_g_gaussian vector to pe_g: */
-				for( i=0; i<numdofs; i++)pe_g[i]+=pe_g_gaussian[i];
+				for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
 
 			} //for (ig2=0; ig2<num_vert_gauss; ig2++)
@@ -1477,5 +1775,5 @@
 
 	/*Add pe_g to global vector pg: */
-	VecSetValues(pg,numdofs,doflist,(const double*)pe_g,ADD_VALUES);
+	VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
 
 	cleanup_and_return: 
@@ -1488,4 +1786,5 @@
 
 }
+
 
 #undef __FUNCT__ 
@@ -1554,6 +1853,6 @@
 	/* node data: */
 	const int    numgrids=6;
-	const int    numdofs=2*numgrids;
-	int          doflist[numdofs];
+	const int    numdof=2*numgrids;
+	int          doflist[numdof];
 	int          nodedofs[2];
 	int          numberofdofspernode;
@@ -1604,6 +1903,6 @@
 	const int    numgrids=6;
 	const int    NDOF1=1;
-	const int    numdofs=NDOF1*numgrids;
-	int          doflist[numdofs];
+	const int    numdof=NDOF1*numgrids;
+	int          doflist[numdof];
 	int          nodedof;
 	int          numberofdofspernode;
@@ -1700,7 +1999,7 @@
 	const int    numgrids=6;
 	const int    NDOF1=1;
-	const int    numdofs=NDOF1*numgrids;
+	const int    numdof=NDOF1*numgrids;
 	double       xyz_list[numgrids][3];
-	int          doflist[numdofs];
+	int          doflist[numdof];
 	int          numberofdofspernode;
 	
@@ -1725,6 +2024,6 @@
 
 	/*element vector at the gaussian points: */
-	double  pe_g[numdofs];
-	double  pe_g_gaussian[numdofs];
+	double  pe_g[numdof];
+	double  pe_g_gaussian[numdof];
 	double l1l2l3l4l5l6[6];
 
@@ -1760,5 +2059,5 @@
 
 	/* Set pe_g to 0: */
-	for(i=0;i<numdofs;i++) pe_g[i]=0.0;
+	for(i=0;i<numdof;i++) pe_g[i]=0.0;
 
 	/* recover input parameters: */
@@ -1816,5 +2115,5 @@
 
 			/*Add pe_g_gaussian vector to pe_g: */
-			for( i=0; i<numdofs; i++)pe_g[i]+=pe_g_gaussian[i];
+			for( i=0; i<numdof; i++)pe_g[i]+=pe_g_gaussian[i];
 
 		} //for (ig2=0; ig2<num_vert_gauss; ig2++)
@@ -1822,5 +2121,5 @@
 
 	/*Add pe_g to global vector pg: */
-	VecSetValues(pg,numdofs,doflist,(const double*)pe_g,ADD_VALUES);
+	VecSetValues(pg,numdof,doflist,(const double*)pe_g,ADD_VALUES);
 
 	cleanup_and_return: 
@@ -1905,2 +2204,930 @@
 }
 
+#undef __FUNCT__ 
+#define __FUNCT__ "ReduceMatrixStokes" 
+void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
+		
+	int i,j;
+
+	double Kii[24][24];
+	double Kib[24][3];
+	double Kbb[3][3];
+	double Kbi[3][24];
+	double Kbbinv[3][3];
+	double KibKbbinv[24][3];
+	double Kright[24][24];
+
+	/*Create the four matrices used for reduction */
+	for(i=0;i<24;i++){
+		for(j=0;j<24;j++){
+			Kii[i][j]=*(Ke_temp+27*i+j);
+		}
+		for(j=0;j<3;j++){
+			Kib[i][j]=*(Ke_temp+27*i+j+24);
+		}
+	}
+	for(i=0;i<3;i++){
+		for(j=0;j<24;j++){
+			Kbi[i][j]=*(Ke_temp+27*(i+24)+j);
+		}
+		for(j=0;j<3;j++){
+			Kbb[i][j]=*(Ke_temp+27*(i+24)+j+24);
+		}
+	}
+
+	/*Inverse the matrix corresponding to bubble part Kbb */
+	GetMatrixInvert(&Kbbinv[0][0], &Kbb[0][0]);
+
+	/*Multiply matrices to create the reduce matrix Ke_reduced */
+	MatrixMultiply(&Kib[0][0],24,3,0,&Kbbinv[0][0],3,3,0,&KibKbbinv[0][0],0);
+	MatrixMultiply(&KibKbbinv[0][0],24,3,0,&Kbi[0][0],3,24,0,&Kright[0][0],0);
+
+	/*Affect value to the reduced matrix */
+	for(i=0;i<24;i++){
+		for(j=0;j<24;j++){
+			*(Ke_reduced+24*i+j)=Kii[i][j]-Kright[i][j];
+		}
+	}
+
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "GetMatrixInvert"
+void Penta::GetMatrixInvert(double*  Ke_invert, double* Ke){
+	/*Inverse a 3 by 3 matrix only */
+
+	double a,b,c,d,e,f,g,h,i;
+	double det;
+	int calculationdof=3;
+	
+	/*Take the matrix components: */
+	a=*(Ke+calculationdof*0+0);
+	b=*(Ke+calculationdof*0+1);
+	c=*(Ke+calculationdof*0+2);
+	d=*(Ke+calculationdof*1+0);
+	e=*(Ke+calculationdof*1+1);
+	f=*(Ke+calculationdof*1+2);
+	g=*(Ke+calculationdof*2+0);
+	h=*(Ke+calculationdof*2+1);
+	i=*(Ke+calculationdof*2+2);
+
+	det=a*(e*i-f*h)-b*(d*i-f*g)+c*(d*h-e*g);
+	
+	*(Ke_invert+calculationdof*0+0)=(e*i-f*h)/det;
+	*(Ke_invert+calculationdof*0+1)=(c*h-b*i)/det;
+	*(Ke_invert+calculationdof*0+2)=(b*f-c*e)/det;
+	*(Ke_invert+calculationdof*1+0)=(f*g-d*i)/det;
+	*(Ke_invert+calculationdof*1+1)=(a*i-c*g)/det;
+	*(Ke_invert+calculationdof*1+2)=(c*d-a*f)/det;
+	*(Ke_invert+calculationdof*2+0)=(d*h-e*g)/det;
+	*(Ke_invert+calculationdof*2+1)=(b*g-a*h)/det;
+	*(Ke_invert+calculationdof*2+2)=(a*e-b*d)/det;
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::SurfaceNormal"
+
+void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
+
+	int i;
+	double v13[3];
+	double v23[3];
+	double normal[3];
+	double normal_norm;
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+
+	normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
+
+	*(surface_normal)=normal[0]/normal_norm;
+	*(surface_normal+1)=normal[1]/normal_norm;
+	*(surface_normal+2)=normal[2]/normal_norm;
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetStrainRateStokes"
+void Penta::GetStrainRateStokes(double* epsilon, double* velocity, double* xyz_list, double* gauss_coord){
+
+	int i,j;
+
+	int numgrids=6;
+	int DOFVELOCITY=3;
+	double B[8][27];
+	double B_reduced[numgrids][DOFVELOCITY*numgrids];
+
+	/*Get B matrix: */
+	GetBStokes(&B[0][0], xyz_list, gauss_coord);
+
+	/*Create a reduced matrix of B to get rid of pressure */
+	for (i=0;i<6;i++){
+		for (j=0;j<3;j++){
+			B_reduced[i][j]=B[i][j];
+		}
+		for (j=4;j<7;j++){
+			B_reduced[i][j-1]=B[i][j];
+		}
+		for (j=8;j<11;j++){
+			B_reduced[i][j-2]=B[i][j];
+		}
+		for (j=12;j<15;j++){
+			B_reduced[i][j-3]=B[i][j];
+		}
+		for (j=16;j<19;j++){
+			B_reduced[i][j-4]=B[i][j];
+		}
+		for (j=20;j<23;j++){
+			B_reduced[i][j-5]=B[i][j];
+		}
+	}
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply( &B_reduced[0][0],6,DOFVELOCITY*numgrids, 0, velocity,DOFVELOCITY*numgrids,1,0,epsilon, 0);
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetBStokes"
+void Penta::GetBStokes(double* B, double* xyz_list, double* gauss_coord){
+
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 3*DOFPERGRID. 
+	 * For grid i, Bi can be expressed in the basic coordinate system
+	 * by: 				Bi_basic=[ dh/dx          0             0       0  ]
+		*					[   0           dh/dy           0       0  ]
+		*					[   0             0           dh/dy     0  ]
+		*					[ 1/2*dh/dy    1/2*dh/dx        0       0  ]
+		*					[ 1/2*dh/dz       0         1/2*dh/dx   0  ]
+		*					[   0          1/2*dh/dz    1/2*dh/dy   0  ]
+		*					[   0             0             0       h  ]
+		*					[ dh/dx         dh/dy         dh/dz     0  ]
+		*	where h is the interpolation function for grid i.
+		*	Same thing for Bb except the last column that does not exist.
+		*/
+	
+	int i;
+	int calculationdof=3;
+	int numgrids=6;
+	int DOFPERGRID=4;
+
+	double dh1dh7_basic[calculationdof][numgrids+1];
+	double l1l6[numgrids];
+
+
+	/*Get dh1dh7 in basic coordinate system: */
+	GetNodalFunctionsDerivativesBasicStokes(&dh1dh7_basic[0][0],xyz_list, gauss_coord);
+
+	GetNodalFunctions(l1l6, gauss_coord);
+	
+	#ifdef _DEBUG_ 
+	for (i=0;i<6;i++){
+		printf("Node %i  dh/dx=%lf dh/dy=%lf dh/dz=%lf \n",i,dh1dh7_basic[0][i],dh1dh7_basic[1][i]);
+	}
+
+	#endif
+
+	/*Build B: */
+	for (i=0;i<numgrids+1;i++){
+		*(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7_basic[0][i]; //B[0][DOFPERGRID*i]=dh1dh6_basic[0][i];
+		*(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
+		*(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
+		*(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
+		*(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7_basic[1][i];
+		*(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
+		*(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
+		*(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
+		*(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7_basic[2][i];
+		*(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=(float).5*dh1dh7_basic[1][i]; 
+		*(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=(float).5*dh1dh7_basic[0][i]; 
+		*(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
+		*(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=(float).5*dh1dh7_basic[2][i];
+		*(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
+		*(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=(float).5*dh1dh7_basic[0][i];
+		*(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
+		*(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=(float).5*dh1dh7_basic[2][i];
+		*(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=(float).5*dh1dh7_basic[1][i];
+		*(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=0;
+		*(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=0;
+		*(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=0;
+		*(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=dh1dh7_basic[0][i];
+		*(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=dh1dh7_basic[1][i];
+		*(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=dh1dh7_basic[2][i];
+	}
+
+	for (i=0;i<numgrids;i++){ //last column not for the bubble function
+		*(B+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
+		*(B+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=l1l6[i];
+		*(B+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=0;
+	}
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetBprimeStokes"
+void Penta::GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss_coord){
+
+	/*	Compute B'  matrix. B'=[B1' B2' B3' B4' B5' B6' Bb'] where Bi' is of size 3*NDOF2. 
+	*	For grid i, Bi' can be expressed in the basic coordinate system
+	*	by: 
+	*				Bi_basic'=[ dh/dx   0          0       0]
+	*					 [   0      dh/dy      0       0]
+	*					 [   0      0         dh/dz    0]
+	*					 [  dh/dy   dh/dx      0       0]
+	*					 [  dh/dz   0        dh/dx     0]
+	*					 [   0      dh/dz    dh/dy     0]
+	*					 [  dh/dx   dh/dy    dh/dz     0]
+	*					 [   0      0          0       h]
+	*	where h is the interpolation function for grid i.
+	*
+	* 	Same thing for the bubble fonction except that there is no fourth column
+	*/
+
+	int i;
+	int calculationdof=3;
+	int numgrids=6;
+	int DOFPERGRID=4;
+
+	double dh1dh7_basic[calculationdof][numgrids+1];
+	double l1l6[numgrids];
+
+
+	/*Get dh1dh7 in basic coordinate system: */
+	GetNodalFunctionsDerivativesBasicStokes(&dh1dh7_basic[0][0],xyz_list, gauss_coord);
+
+	GetNodalFunctions(l1l6, gauss_coord);
+	
+	#ifdef _DEBUG_ 
+	for (i=0;i<6;i++){
+		printf("Node %i  dh/dx=%lf dh/dy=%lf dh/dz=%lf \n",i,dh1dh7_basic[0][i],dh1dh7_basic[1][i]);
+	}
+
+	#endif
+
+	/*B_primeuild B_prime: */
+	for (i=0;i<numgrids+1;i++){
+		*(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i)=dh1dh7_basic[0][i]; //B_prime[0][DOFPERGRID*i]=dh1dh6_basic[0][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+1)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+2)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+1)=dh1dh7_basic[1][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+2)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+1)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+2)=dh1dh7_basic[2][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i)=dh1dh7_basic[1][i]; 
+		*(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+1)=dh1dh7_basic[0][i]; 
+		*(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+2)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i)=dh1dh7_basic[2][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+1)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+2)=dh1dh7_basic[0][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+1)=dh1dh7_basic[2][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+2)=dh1dh7_basic[1][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i)=dh1dh7_basic[0][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+1)=dh1dh7_basic[1][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+2)=dh1dh7_basic[2][i];
+		*(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+1)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+2)=0;
+	}
+
+	for (i=0;i<numgrids;i++){ //last column not for the bubble function
+		*(B_prime+(DOFPERGRID*numgrids+3)*0+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*1+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*2+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*3+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*4+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*5+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*6+DOFPERGRID*i+3)=0;
+		*(B_prime+(DOFPERGRID*numgrids+3)*7+DOFPERGRID*i+3)=l1l6[i];
+	}
+
+}
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetLStokes"
+void Penta::GetLStokes(double* LStokes, double* gauss_coord_tria){
+
+	/*
+	* Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	* For grid i, Li can be expressed in the basic coordinate system
+	* by: 
+	*       Li_basic=[ h    0    0   0]
+	*	 	 [ 0    h    0   0]
+	*		 [ 0    0    h   0]
+	*		 [ 0    0    h   0]
+	*	 	 [ h    0    0   0]
+	*	 	 [ 0    h    0   0]
+	*	 	 [ h    0    0   0]
+	*	 	 [ 0    h    0   0]
+	*		 [ 0    0    h   0]
+	*		 [ 0    0    h   0]
+	*		 [ 0    0    h   0]
+	*	 	 [ h    0    0   0]
+	*	 	 [ 0    h    0   0]
+	*		 [ 0    0    h   0]
+	* where h is the interpolation function for grid i.
+	*/
+
+	int i;
+	int numgrids2d=3;
+	int num_dof=4;
+
+	double l1l2l3[numgrids2d];
+
+
+	/*Get l1l2l3 in basic coordinate system: */
+	l1l2l3[0]=gauss_coord_tria[0];
+	l1l2l3[1]=gauss_coord_tria[1];
+	l1l2l3[2]=gauss_coord_tria[2];
+	
+
+	#ifdef _DELUG_ 
+	for (i=0;i<3;i++){
+		printf("Node %i  h=%lf \n",i,l1l2l3[i]);
+	}
+	#endif
+
+	/*Build LStokes: */
+	for (i=0;i<3;i++){
+		*(LStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LStokes[0][NDOF2*i]=dh1dh2dh3_basic[0][i];
+		*(LStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*1+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*2+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*2+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*3+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*3+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*3+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*4+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*4+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*5+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*5+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*5+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*6+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*6+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*7+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*7+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*7+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*8+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*8+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*9+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*9+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*10+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*10+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*10+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*11+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*11+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*12+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*12+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
+		*(LStokes+num_dof*numgrids2d*12+num_dof*i+3)=0;
+		*(LStokes+num_dof*numgrids2d*13+num_dof*i)=0;
+		*(LStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
+		*(LStokes+num_dof*numgrids2d*13+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*numgrids2d*13+num_dof*i+3)=0;
+	
+	}
+}
+
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetLprimeStokes"
+void Penta::GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_coord_tria, double* gauss_coord){
+
+	/*
+	* Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof. 
+	* For grid i, Lpi can be expressed in the basic coordinate system
+	* by: 
+	*       Lpi_basic=[ h    0    0   0]
+	*		 [ 0    h    0   0]
+	*		 [ h    0    0   0]
+	*		 [ 0    h    0   0]
+	*		 [ 0    0    h   0]
+	*		 [ 0    0    h   0]
+	*		 [ 0    0  dh/dz 0]
+	*		 [ 0    0  dh/dz 0]
+	*		 [ 0    0  dh/dz 0]
+	*		 [dh/dz 0  dh/dx 0]
+	*		 [ 0 dh/dz dh/dy 0]
+	* 		 [ 0    0    0   h]
+	* 		 [ 0    0    0   h]
+	* 		 [ 0    0    0   h]
+	* where h is the interpolation function for grid i.
+	*/
+
+	int i;
+	int numgrids2d=3;
+	int num_dof=4;
+
+	double l1l2l3[numgrids2d];
+	double dh1dh6_basic[3][6];
+
+
+	/*Get l1l2l3 in basic coordinate system: */
+	l1l2l3[0]=gauss_coord_tria[0];
+	l1l2l3[1]=gauss_coord_tria[1];
+	l1l2l3[2]=gauss_coord_tria[2];
+	
+	GetNodalFunctionsDerivativesBasic(&dh1dh6_basic[0][0],xyz_list,gauss_coord);
+
+	#ifdef _DELUG_ 
+	for (i=0;i<3;i++){
+		printf("Node %i  h=%lf \n",i,l1l2l3[i]);
+	}
+	#endif
+
+	/*Build LprimeStokes: */
+	for (i=0;i<3;i++){
+		*(LprimeStokes+num_dof*numgrids2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh2dh3_basic[0][i];
+		*(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*0+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*1+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*1+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*2+num_dof*i)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*2+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*3+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*3+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*4+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*4+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*5+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*5+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*6+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+2)=dh1dh6_basic[2][i];
+		*(LprimeStokes+num_dof*numgrids2d*6+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*7+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+2)=dh1dh6_basic[2][i];
+		*(LprimeStokes+num_dof*numgrids2d*7+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*8+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+2)=dh1dh6_basic[2][i];
+		*(LprimeStokes+num_dof*numgrids2d*8+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*9+num_dof*i)=dh1dh6_basic[2][i];
+		*(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+2)=dh1dh6_basic[0][i];
+		*(LprimeStokes+num_dof*numgrids2d*9+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*10+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+1)=dh1dh6_basic[2][i];
+		*(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+2)=dh1dh6_basic[1][i];
+		*(LprimeStokes+num_dof*numgrids2d*10+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*numgrids2d*11+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*11+num_dof*i+3)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*12+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*12+num_dof*i+3)=l1l2l3[i];
+		*(LprimeStokes+num_dof*numgrids2d*13+num_dof*i)=0;
+		*(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*numgrids2d*13+num_dof*i+3)=l1l2l3[i];
+	
+	}
+	
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetNodalFunctionsDerivativesBasicStokes"
+void Penta::GetNodalFunctionsDerivativesBasicStokes(double* dh1dh7_basic,double* xyz_list, double* gauss_coord){
+	
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * basic coordinate system: */
+
+	int i;
+
+	int numgrids=7;
+	double dh1dh7_param[3][numgrids];
+	double Jinv[3][3];
+
+
+	/*Get derivative values with respect to parametric coordinate system: */
+	GetNodalFunctionsDerivativesParamsStokes(&dh1dh7_param[0][0], gauss_coord); 
+
+	/*Get Jacobian invert: */
+	GetJacobianInvert(&Jinv[0][0], xyz_list, gauss_coord);
+
+	/*Build dh1dh6_basic: 
+	 *
+	 * [dhi/dx]= Jinv'*[dhi/dr]
+	 * [dhi/dy]        [dhi/ds]
+	 * [dhi/dz]        [dhi/dzeta]
+	 */
+
+	for (i=0;i<numgrids;i++){
+		*(dh1dh7_basic+numgrids*0+i)=Jinv[0][0]*dh1dh7_param[0][i]+Jinv[1][0]*dh1dh7_param[1][i]+Jinv[2][0]*dh1dh7_param[2][i];
+		*(dh1dh7_basic+numgrids*1+i)=Jinv[0][1]*dh1dh7_param[0][i]+Jinv[1][1]*dh1dh7_param[1][i]+Jinv[2][1]*dh1dh7_param[2][i];
+		*(dh1dh7_basic+numgrids*2+i)=Jinv[0][2]*dh1dh7_param[0][i]+Jinv[1][2]*dh1dh7_param[1][i]+Jinv[2][2]*dh1dh7_param[2][i];
+	}
+
+}
+
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetNodalFunctionsDerivativesParamsStokes"
+void Penta::GetNodalFunctionsDerivativesParamsStokes(double* dl1dl7,double* gauss_coord){
+	
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * natural coordinate system) at the gaussian point. */
+
+	double sqrt3=sqrt(3.0);
+	int    numgrids=7; //six plus bubble grids
+
+	double r=gauss_coord[1]-gauss_coord[0];
+	double s=-3.0/sqrt3*(gauss_coord[0]+gauss_coord[1]-2.0/3.0);
+	double zeta=gauss_coord[3];
+
+	/*First nodal function: */
+	*(dl1dl7+numgrids*0+0)=-1.0/2.0*(1.0-zeta)/2.0;
+	*(dl1dl7+numgrids*1+0)=-sqrt3/6.0*(1.0-zeta)/2.0;
+	*(dl1dl7+numgrids*2+0)=-1.0/2.0*(-1.0/2.0*r-sqrt3/6.0*s+1.0/3.0);
+
+	/*Second nodal function: */
+	*(dl1dl7+numgrids*0+1)=1.0/2.0*(1.0-zeta)/2.0;
+	*(dl1dl7+numgrids*1+1)=-sqrt3/6.0*(1.0-zeta)/2.0;
+	*(dl1dl7+numgrids*2+1)=-1.0/2.0*(1.0/2.0*r-sqrt3/6.0*s+1.0/3.0);
+
+	/*Third nodal function: */
+	*(dl1dl7+numgrids*0+2)=0;
+	*(dl1dl7+numgrids*1+2)=sqrt3/3.0*(1.0-zeta)/2.0;
+	*(dl1dl7+numgrids*2+2)=-1.0/2.0*(sqrt3/3.0*s+1.0/3.0);
+
+	/*Fourth nodal function: */
+	*(dl1dl7+numgrids*0+3)=-1.0/2.0*(1.0+zeta)/2.0;
+	*(dl1dl7+numgrids*1+3)=-sqrt3/6.0*(1.0+zeta)/2.0;
+	*(dl1dl7+numgrids*2+3)=1.0/2.0*(-1.0/2.0*r-sqrt3/6.0*s+1.0/3.0);
+
+	/*Fith nodal function: */
+	*(dl1dl7+numgrids*0+4)=1.0/2.0*(1.0+zeta)/2.0;
+	*(dl1dl7+numgrids*1+4)=-sqrt3/6.0*(1.0+zeta)/2.0;
+	*(dl1dl7+numgrids*2+4)=1.0/2.0*(1.0/2.0*r-sqrt3/6.0*s+1.0/3.0);
+
+	/*Sixth nodal function: */
+	*(dl1dl7+numgrids*0+5)=0;
+	*(dl1dl7+numgrids*1+5)=sqrt3/3.0*(1.0+zeta)/2.0;
+	*(dl1dl7+numgrids*2+5)=1.0/2.0*(sqrt3/3.0*s+1.0/3.0);
+
+	/*Seventh nodal function: */
+	*(dl1dl7+numgrids*0+6)=9.0/2.0*r*(1.0+zeta)*(zeta-1.0)*(sqrt3*s+1.0);
+	*(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));
+	*(dl1dl7+numgrids*2+6)=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(-2.0*zeta);
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::CreatePVectorDiagnosticStokes"
+void Penta::CreatePVectorDiagnosticStokes( Vec pg, void* vinputs,int analysis_type){
+
+
+	/*indexing: */
+	int i,j;
+
+	int numgrids=6;
+	int DOFPERGRID=4;
+	int numdof=numgrids*DOFPERGRID;
+	int numgrids2d=3;
+	int numdof2d=numgrids2d*DOFPERGRID;
+	int doflist[numdof];
+	int numberofdofspernode;
+
+	/*Material properties: */
+	double         gravity,rho_ice,rho_water;
+
+	/*parameters: */
+	double		   xyz_list_tria[numgrids2d][3];
+	double         xyz_list[numgrids][3];
+	double		   surface_normal[3];
+	double		   bed_normal[3];
+	double         bed;
+	double         vxvyvz_list[numgrids][3];
+
+	/* gaussian points: */
+	int     num_area_gauss;
+	int     igarea,igvert;
+	double* first_gauss_area_coord  =  NULL;
+	double* second_gauss_area_coord =  NULL;
+	double* third_gauss_area_coord  =  NULL;
+	double* vert_gauss_coord = NULL;
+	double* area_gauss_weights  =  NULL;
+	double* vert_gauss_weights  =  NULL;
+
+	/* specific gaussian point: */
+	double  gauss_weight,area_gauss_weight,vert_gauss_weight;
+	double  gauss_coord[4];
+	double  gauss_coord_tria[3];
+
+	int     area_order=5;
+	int	  num_vert_gauss=5;
+	
+	double  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double  viscosity;
+	double  water_pressure;
+	int     dofs[3]={0,1,2};
+
+	/*matrices: */
+	double     Pe_temp[27]; //for the six nodes and the bubble 
+	double     Pe_gaussian[27]; //for the six nodes and the bubble 
+	double     Ke_temp[27][3]; //for the six nodes and the bubble 
+	double     Pe_reduced[numdof]; //for the six nodes only
+	double     Ke_gaussian[27][3];
+	double     L[3]; //for the three nodes of the bed
+	double     l1l7[7]; //for the six nodes and the bubble 
+	double     B[8][27];
+	double     B_prime[8][27];
+	double     B_prime_bubble[8][3];
+	double     Jdet;
+	double     Jdet2d;
+	double     D[8][8]={{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 },{ 0,0,0,0,0,0,0,0 }};          
+	double     D_scalar;
+	double     tBD[27][8];
+	double     P_terms[numdof];
+	
+	ParameterInputs* inputs=NULL;
+	Tria*            tria=NULL;
+
+	/*recover pointers: */
+	inputs=(ParameterInputs*)vinputs;
+
+	/* Set P_terms to 0: */
+	for(i=0;i<numdof;i++){
+		P_terms[i]=0;
+	}	
+
+	/*recovre material parameters: */
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+
+	/*recover extra inputs from users, at current convergence iteration: */
+	inputs->Recover("velocity",&vxvyvz_list[0][0],3,dofs,numgrids,(void**)nodes);
+
+	/* Get node coordinates and dof list: */
+	GetElementNodeData( &xyz_list[0][0], nodes, numgrids);
+	GetDofList(&doflist[0],&numberofdofspernode);
+
+	/*Initialize Ke_temp to zero befor adding terms */
+	for (i=0;i<27;i++){
+		Pe_temp[i]=0;
+		for (j=0;j<3;j++){
+			Ke_temp[i][j]=0;
+		}
+	}
+
+	
+	
+	/* Get gaussian points and weights. Penta is an extrusion of a Tria, we therefore 
+	   get tria gaussian points as well as segment gaussian points. For tria gaussian 
+	   points, order of integration is 2, because we need to integrate the product tB*D*B' 
+	   which is a polynomial of degree 3 (see GaussTria for more details). For segment gaussian 
+	   points, same deal, which yields 3 gaussian points.*/
+
+	
+
+	/* Get gaussian points and weights (make this a statically initialized list of points? fstd): */
+	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);
+
+	/* Start  looping on the number of gaussian points: */
+	for (igarea=0; igarea<num_area_gauss; igarea++){
+		for (igvert=0; igvert<num_vert_gauss; igvert++){
+			/*Pick up the gaussian point: */
+			area_gauss_weight=*(area_gauss_weights+igarea);
+			vert_gauss_weight=*(vert_gauss_weights+igvert);
+			gauss_weight=area_gauss_weight*vert_gauss_weight;
+			gauss_coord[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord[2]=*(third_gauss_area_coord+igarea);
+			gauss_coord[3]=*(vert_gauss_coord+igvert);
+
+			/*Compute strain rate and viscosity: */
+			GetStrainRateStokes(&epsilon[0],&vxvyvz_list[0][0],&xyz_list[0][0],gauss_coord);
+			matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		
+			/* Get Jacobian determinant: */
+			GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss_coord);
+
+			/* Get nodal functions */
+			GetNodalFunctionsStokes(&l1l7[0], gauss_coord);
+
+			/* Build gaussian vector */
+			for(i=0;i<numgrids+1;i++){
+				Pe_gaussian[i*DOFPERGRID+2]=-rho_ice*gravity*Jdet*gauss_weight*l1l7[i];
+			}
+
+			/*Add Pe_gaussian to terms in Pe_temp. Watch out for column orientation from matlab: */
+			for(i=0;i<27;i++){
+				Pe_temp[i]+=Pe_gaussian[i];
+			}
+
+			/*Get B and Bprime matrices: */
+			GetBStokes(&B[0][0],&xyz_list[0][0],gauss_coord); 
+			GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss_coord); 
+			
+			/*Get bubble part of Bprime */
+			for(i=0;i<8;i++){
+				for(j=0;j<3;j++){
+					B_prime_bubble[i][j]=B_prime[i][j+24];
+				}
+			}
+
+			/* Build the D matrix: we plug the gaussian weight, the thickness, the viscosity, and the jacobian determinant 
+			 * onto this scalar matrix, so that we win some computational time: */
+			D_scalar=gauss_weight*Jdet;
+			for (i=0;i<6;i++){
+				D[i][i]=D_scalar*viscosity;
+			}
+			for (i=6;i<8;i++){
+				D[i][i]=-D_scalar*stokesreconditioning;
+			}
+
+			/*  Do the triple product tB*D*Bprime: */
+			MatrixMultiply(&B[0][0],8,27,1,&D[0][0],8,8,0,&tBD[0][0],0);
+			MatrixMultiply(&tBD[0][0],27,8,0,&B_prime_bubble[0][0],8,3,0,&Ke_gaussian[0][0],0);
+
+			/*Add Ke_gaussian and Ke_gaussian to terms in pKe. Watch out for column orientation from matlab: */
+			for(i=0;i<27;i++){
+				for(j=0;j<3;j++){
+					Ke_temp[i][j]+=Ke_gaussian[i][j];
+				}
+			}
+		}
+	}
+
+
+	/*Deal with 2d friction at the bedrock interface: */
+	if ( (onbed==1) && (shelf==1)){
+
+		for(i=0;i<numgrids2d;i++){
+			for(j=0;j<3;j++){
+				xyz_list_tria[i][j]=xyz_list[i][j];
+			}
+		}
+
+		GaussTria (&num_area_gauss, &first_gauss_area_coord, &second_gauss_area_coord, &third_gauss_area_coord, &area_gauss_weights, 2);
+
+		/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+		for (igarea=0; igarea<num_area_gauss; igarea++){
+			gauss_weight=*(area_gauss_weights+igarea);
+			gauss_coord[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord[2]=*(third_gauss_area_coord+igarea);
+			gauss_coord[3]=-1;
+			
+			gauss_coord_tria[0]=*(first_gauss_area_coord+igarea); 
+			gauss_coord_tria[1]=*(second_gauss_area_coord+igarea);
+			gauss_coord_tria[2]=*(third_gauss_area_coord+igarea);
+			
+
+			/*Get the Jacobian determinant */
+			tria->GetJacobianDeterminant3d(&Jdet2d, &xyz_list_tria[0][0], gauss_coord_tria);
+			
+			/* Get bed at gaussian point */
+			GetParameterValue(&bed,&b[0],gauss_coord);
+
+			/*Get L matrix : */
+			tria->GetL(&L[0], &xyz_list[0][0], gauss_coord_tria,1);
+				
+			/*Get water_pressure at gaussian point */
+			water_pressure=gravity*rho_water*bed;
+
+			/*Get normal vecyor to the bed */
+			SurfaceNormal(&surface_normal[0],xyz_list_tria);
+			
+			bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
+			bed_normal[1]=-surface_normal[1];
+			bed_normal[2]=-surface_normal[2];
+
+			for(i=0;i<numgrids2d;i++){
+				for(j=0;j<3;j++){
+					Pe_temp[i*DOFPERGRID+j]+=water_pressure*gauss_weight*Jdet2d*L[i]*bed_normal[j];
+				}
+			}
+		}
+	} //if ( (onbed==1) && (shelf==1))
+	
+	/*Reduce the matrix */
+	ReduceVectorStokes(&Pe_reduced[0], &Ke_temp[0][0], &Pe_temp[0]);
+
+	for(i=0;i<numdof;i++){
+		P_terms[i]+=Pe_reduced[i];
+	}
+
+
+	/*Add P_terms to global vector pg: */
+	VecSetValues(pg,numdof,doflist,(const double*)P_terms,ADD_VALUES);
+
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::ReduceVectorStokes" 
+void Penta::ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp){
+		
+	int i,j;
+
+	double Pi[24];
+	double Pb[3];
+	double Kbb[3][3];
+	double Kib[24][3];
+	double Kbbinv[3][3];
+	double KibKbbinv[24][3];
+	double Pright[24];
+
+	/*Create the four matrices used for reduction */
+	for(i=0;i<24;i++){
+		Pi[i]=*(Pe_temp+i);
+	}
+	for(i=0;i<3;i++){
+		Pb[i]=*(Pe_temp+i+24);
+	}
+	for(j=0;j<3;j++){
+		for(i=0;i<24;i++){
+			Kib[i][j]=*(Ke_temp+3*i+j);
+		}
+		for(i=0;i<3;i++){
+			Kbb[i][j]=*(Ke_temp+3*(i+24)+j);
+		}
+	}
+
+	/*Inverse the matrix corresponding to bubble part Kbb */
+	GetMatrixInvert(&Kbbinv[0][0], &Kbb[0][0]);
+
+	/*Multiply matrices to create the reduce matrix Ke_reduced */
+	MatrixMultiply(&Kib[0][0],24,3,0,&Kbbinv[0][0],3,3,0,&KibKbbinv[0][0],0);
+	MatrixMultiply(&KibKbbinv[0][0],24,3,0,&Pb[0],3,1,0,&Pright[0],0);
+
+	/*Affect value to the reduced matrix */
+	for(i=0;i<24;i++){
+		*(Pe_reduced+i)=Pi[i]-Pright[i];
+	}
+}
+
+#undef __FUNCT__ 
+#define __FUNCT__ "Penta::GetNodalFunctionsStokes" 
+void Penta::GetNodalFunctionsStokes(double* l1l7, double* gauss_coord){
+	
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	/*First nodal function: */
+	l1l7[0]=gauss_coord[0]*(1.0-gauss_coord[3])/2.0;
+
+	/*Second nodal function: */
+	l1l7[1]=gauss_coord[1]*(1.0-gauss_coord[3])/2.0;
+
+	/*Third nodal function: */
+	l1l7[2]=gauss_coord[2]*(1.0-gauss_coord[3])/2.0;
+
+	/*Fourth nodal function: */
+	l1l7[3]=gauss_coord[0]*(1.0+gauss_coord[3])/2.0;
+
+	/*Fifth nodal function: */
+	l1l7[4]=gauss_coord[1]*(1.0+gauss_coord[3])/2.0;
+
+	/*Sixth nodal function: */
+	l1l7[5]=gauss_coord[2]*(1.0+gauss_coord[3])/2.0;
+
+	/*Seventh nodal function: */
+	l1l7[6]=27*gauss_coord[0]*gauss_coord[1]*gauss_coord[2]*(1.0+gauss_coord[3])*(1.0-gauss_coord[3]);
+
+}
Index: /issm/trunk/src/c/objects/Penta.h
===================================================================
--- /issm/trunk/src/c/objects/Penta.h	(revision 393)
+++ /issm/trunk/src/c/objects/Penta.h	(revision 394)
@@ -116,4 +116,19 @@
 		void  CreatePVectorSlopeCompute( Vec pg, void* vinputs, int analysis_type);
 
+		void  CreateKMatrixDiagnosticStokes( Mat Kgg, void* vinputs, int analysis_type);
+		void  CreatePVectorDiagnosticStokes( Vec pg, void* vinputs,int analysis_type);
+		void  ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp);
+		void  GetMatrixInvert(double*  Ke_invert, double* Ke);
+		void  SurfaceNormal(double* surface_normal, double xyz_list[3][3]);
+		void  GetStrainRateStokes(double* epsilon, double* velocity, double* xyz_list, double* gauss_coord);
+		void  GetBStokes(double* B, double* xyz_list, double* gauss_coord);
+		void  GetBprimeStokes(double* B_prime, double* xyz_list, double* gauss_coord);
+		void  GetLStokes(double* LStokes, double* gauss_coord_tria);
+		void  GetLprimeStokes(double* LprimeStokes, double* xyz_list, double* gauss_coord_tria, double* gauss_coord);
+		void  GetNodalFunctionsDerivativesBasicStokes(double* dh1dh7_basic,double* xyz_list, double* gauss_coord);
+		void  GetNodalFunctionsDerivativesParamsStokes(double* dl1dl7,double* gauss_coord);
+		void  ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp);
+		void  GetNodalFunctionsStokes(double* l1l7, double* gauss_coord);
+
 
 };
Index: /issm/trunk/src/m/solutions/cielo/diagnostic_core.m
===================================================================
--- /issm/trunk/src/m/solutions/cielo/diagnostic_core.m	(revision 393)
+++ /issm/trunk/src/m/solutions/cielo/diagnostic_core.m	(revision 394)
@@ -42,5 +42,5 @@
 
 end
-
+		
 if ismacayealpattyn,
 
@@ -83,10 +83,13 @@
 		inputs=add(inputs,'bedslopey',slopey,'doublevec',m_sl.parameters.numberofdofspernode,m_sl.parameters.numberofnodes);
 		
-		inputs=add(inputs,'velocity',u_g,'doublevec',m_dh.parameters.numberofdofspernode,m_dh.parameters.numberofnodes);
-		inputs=add(inputs,'pressure',p_g,'doublevec',1,m_dh.parameters.numberofnodes);
+		%recombine u_g and p_g: 
+		u_g_stokes=zeros(m_ds.nodesets.gsize,1);
+		u_g_stokes(dofsetgen([1,2,3],4,m_ds.nodesets.gsize))=u_g;
+		u_g_stokes(dofsetgen([4],4,m_ds.nodesets.gsize))=p_g;
+
+		inputs=add(inputs,'velocity',u_g_stokes,'doublevec',4,m_ds.parameters.numberofnodes);
 
 		displaystring(debug,'\n%s',['update boundary conditions for stokes using velocities previously computed...']);
-		m_ds.y_g(dofsetgen([1,2],4,m_ds.parameters.gsize))=u_g;
-		m_ds.y_g(dofsetgen([3],4,m_ds.parameters.gsize))=u_g_vert;
+		m_ds.y_g(dofsetgen([1,2,3],4,m_ds.nodesets.gsize))=u_g;
 		[m_ds.ys m_ds.ys0]=Reducevectorgtos(m_ds.y_g,m_ds.nodesets);
 
Index: /issm/trunk/src/m/solutions/cielo/diagnostic_core_nonlinear.m
===================================================================
--- /issm/trunk/src/m/solutions/cielo/diagnostic_core_nonlinear.m	(revision 393)
+++ /issm/trunk/src/m/solutions/cielo/diagnostic_core_nonlinear.m	(revision 394)
@@ -12,5 +12,5 @@
 	converged=0;
 
-	soln(count).u_g=get(inputs,'velocity',[1 1 (m.parameters.numberofdofspernode>=3)]); %only keep vz if running with more than 3 dofs per node
+	soln(count).u_g=get(inputs,'velocity',[1 1 (m.parameters.numberofdofspernode>=3) (m.parameters.numberofdofspernode>=3)]); %only keep vz if running with more than 3 dofs per node
 	soln(count).u_f=[];
 
Index: /issm/trunk/src/mex/ModelProcessor/ModelProcessor.cpp
===================================================================
--- /issm/trunk/src/mex/ModelProcessor/ModelProcessor.cpp	(revision 393)
+++ /issm/trunk/src/mex/ModelProcessor/ModelProcessor.cpp	(revision 394)
@@ -39,5 +39,4 @@
 	/*Create loads: */
 	CreateLoads(&loads,model,MODEL);
-
 	/*Create parameters: */
 	CreateParameters(&parameters,model,MODEL);
