void
Albany::STK3DPointStruct::setFieldAndBulkData(
                  const Teuchos::RCP<const Teuchos_Comm>& commT,
                  const Teuchos::RCP<Teuchos::ParameterList>& params,
                  const unsigned int neq_,
                  const AbstractFieldContainer::FieldContainerRequirements& req,
                  const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                  const unsigned int worksetSize,
                  const std::map<std::string,Teuchos::RCP<Albany::StateInfoStruct> >& side_set_sis,
                  const std::map<std::string,AbstractFieldContainer::FieldContainerRequirements>& side_set_req)
{
  std::cout << "---3DPoint::setFieldAndBulkData---" << std::endl;
  SetupFieldData(commT, neq_, req, sis, worksetSize);
  metaData->commit();
  bulkData->modification_begin(); // Begin modifying the mesh
  //TmplSTKMeshStruct<0, albany_stk_mesh_traits<0> >::buildMesh(commT);
  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  singlePartVec[0] = partVec[0]; // Get the element block part to put the element in.
  // Declare element 1 is in that block
  stk::mesh::Entity pt  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, 1, singlePartVec);
  // Declare node 1 is in the node part vector
  stk::mesh::Entity node = bulkData->declare_entity(stk::topology::NODE_RANK, 1, nodePartVec);
  // Declare that the node belongs to the element "pt"
  // "node" is the zeroth node of this element
  bulkData->declare_relation(pt, node, 0);

  bulkData->modification_end();

  fieldAndBulkDataSet = true;
  this->finalizeSideSetMeshStructs(commT, side_set_req, side_set_sis, worksetSize);
}
void
Albany::MpasSTKMeshStruct::constructMesh(
                                               const Teuchos::RCP<const Epetra_Comm>& comm,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const Albany::AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const std::vector<int>& indexToVertexID, const std::vector<double>& verticesCoords, const std::vector<bool>& isVertexBoundary, int nGlobalVertices,
                                               const std::vector<int>& verticesOnTria,
                                               const std::vector<bool>& isBoundaryEdge, const std::vector<int>& trianglesOnEdge, const std::vector<int>& trianglesPositionsOnEdge,
                                               const std::vector<int>& verticesOnEdge,
                                               const std::vector<int>& indexToEdgeID, int nGlobalEdges,
                                               const unsigned int worksetSize)
{
  this->SetupFieldData(comm, neq_, req, sis, worksetSize);

  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  std::cout << "elem_map # elments: " << elem_map->NumMyElements() << std::endl;
  unsigned int ebNo = 0; //element block #??? 
  int sideID = 0;

  AbstractSTKFieldContainer::IntScalarFieldType* proc_rank_field = fieldContainer->getProcRankField();
  AbstractSTKFieldContainer::VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();

  for (int i=0; i<indexToVertexID.size(); i++)
  {
	  stk::mesh::Entity node = bulkData->declare_entity(stk::topology::NODE_RANK, indexToVertexID[i]+1, nodePartVec);

	  double* coord;
	  coord = stk::mesh::field_data(*coordinates_field, node);
	  coord[0] = verticesCoords[3*i];   coord[1] = verticesCoords[3*i+1]; coord[2] = verticesCoords[3*i+2];
  }

  for (int i=0; i<elem_map->NumMyElements(); i++)
  {

     singlePartVec[0] = partVec[ebNo];
     stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_map->GID(i)+1, singlePartVec);

     for(int j=0; j<3; j++)
     {
    	 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, indexToVertexID[verticesOnTria[3*i+j]]+1);
    	 bulkData->declare_relation(elem, node, j);
     }
    
     int* p_rank = (int*)stk::mesh::field_data(*proc_rank_field, elem);
     p_rank[0] = comm->MyPID();
  }

  for (int i=0; i<indexToEdgeID.size(); i++) {

	 if(isBoundaryEdge[i])
	 {

		 singlePartVec[0] = ssPartVec["lateralside"];
		 stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), indexToEdgeID[i]+1, singlePartVec);
		 stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  elem_map->GID(trianglesOnEdge[2*i])+1);
		 bulkData->declare_relation(elem, side,  trianglesPositionsOnEdge[2*i] /*local side id*/);
		 for(int j=0; j<2; j++)
		 {
			 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, indexToVertexID[verticesOnEdge[2*i+j]]+1);
			 bulkData->declare_relation(side, node, j);
		 }
	 }
  }

  bulkData->modification_end();
}
void
Albany::MpasSTKMeshStruct::constructMesh(
                                               const Teuchos::RCP<const Epetra_Comm>& comm,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const Albany::AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const std::vector<int>& indexToVertexID, const std::vector<int>& indexToMpasVertexID, const std::vector<double>& verticesCoords, const std::vector<bool>& isVertexBoundary, int nGlobalVertices,
                                               const std::vector<int>& verticesOnTria,
                                               const std::vector<bool>& isBoundaryEdge, const std::vector<int>& trianglesOnEdge, const std::vector<int>& trianglesPositionsOnEdge,
                                               const std::vector<int>& verticesOnEdge,
                                               const std::vector<int>& indexToEdgeID, int nGlobalEdges,
                                               const std::vector<int>& indexToTriangleID,
                                               const unsigned int worksetSize,
                                               int numLayers, int Ordering)
{
	this->SetupFieldData(comm, neq_, req, sis, worksetSize);

    int elemColumnShift = (Ordering == 1) ? 3 : elem_map->NumGlobalElements()/numLayers;
    int lElemColumnShift = (Ordering == 1) ? 3 : 3*indexToTriangleID.size();
    int elemLayerShift = (Ordering == 0) ? 3 : 3*numLayers;

    int vertexColumnShift = (Ordering == 1) ? 1 : nGlobalVertices;
    int lVertexColumnShift = (Ordering == 1) ? 1 : indexToVertexID.size();
    int vertexLayerShift = (Ordering == 0) ? 1 : numLayers+1;

    int edgeColumnShift = (Ordering == 1) ? 2 : 2*nGlobalEdges;
    int lEdgeColumnShift = (Ordering == 1) ? 1 : indexToEdgeID.size();
    int edgeLayerShift = (Ordering == 0) ? 1 : numLayers;


  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  std::cout << "elem_map # elments: " << elem_map->NumMyElements() << std::endl;
  unsigned int ebNo = 0; //element block #???

  singlePartVec[0] = nsPartVec["Bottom"];

  AbstractSTKFieldContainer::IntScalarFieldType* proc_rank_field = fieldContainer->getProcRankField();
  AbstractSTKFieldContainer::VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();

  for(int i=0; i< (numLayers+1)*indexToVertexID.size(); i++)
  {
	  int ib = (Ordering == 0)*(i%lVertexColumnShift) + (Ordering == 1)*(i/vertexLayerShift);
	  int il = (Ordering == 0)*(i/lVertexColumnShift) + (Ordering == 1)*(i%vertexLayerShift);

	  stk::mesh::Entity node;
	  if(il == 0)
		  node = bulkData->declare_entity(stk::topology::NODE_RANK, il*vertexColumnShift+vertexLayerShift * indexToVertexID[ib]+1, singlePartVec);
	  else
		  node = bulkData->declare_entity(stk::topology::NODE_RANK, il*vertexColumnShift+vertexLayerShift * indexToVertexID[ib]+1, nodePartVec);

      double* coord = stk::mesh::field_data(*coordinates_field, node);
	  coord[0] = verticesCoords[3*ib];   coord[1] = verticesCoords[3*ib+1]; coord[2] = double(il)/numLayers;
  }

  int tetrasLocalIdsOnPrism[3][4];

  for (int i=0; i<elem_map->NumMyElements()/3; i++) {

	 int ib = (Ordering == 0)*(i%(lElemColumnShift/3)) + (Ordering == 1)*(i/(elemLayerShift/3));
	 int il = (Ordering == 0)*(i/(lElemColumnShift/3)) + (Ordering == 1)*(i%(elemLayerShift/3));

	 int shift = il*vertexColumnShift;

	 singlePartVec[0] = partVec[ebNo];


     //TODO: this could be done only in the first layer and then copied into the other layers
     int prismMpasIds[3], prismGlobalIds[6];
     for (int j = 0; j < 3; j++)
	 {
    	 int mpasLowerId = vertexLayerShift * indexToMpasVertexID[verticesOnTria[3*ib+j]];
    	 int lowerId = shift+vertexLayerShift * indexToVertexID[verticesOnTria[3*ib+j]];
    	 prismMpasIds[j] = mpasLowerId;
		 prismGlobalIds[j] = lowerId;
		 prismGlobalIds[j + 3] = lowerId+vertexColumnShift;
	 }

     tetrasFromPrismStructured (prismMpasIds, prismGlobalIds, tetrasLocalIdsOnPrism);


     for(int iTetra = 0; iTetra<3; iTetra++)
     {
    	 stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_map->GID(3*i+iTetra)+1, singlePartVec);
		 for(int j=0; j<4; j++)
		 {
			 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, tetrasLocalIdsOnPrism[iTetra][j]+1);
			 bulkData->declare_relation(elem, node, j);
		 }
		 int* p_rank = (int*)stk::mesh::field_data(*proc_rank_field, elem);
		 p_rank[0] = comm->MyPID();
     }


  }


  singlePartVec[0] = ssPartVec["lateralside"];

  //first we store the lateral faces of prisms, which corresponds to edges of the basal mesh
  int tetraSidePoints[4][3] = {{0, 1, 3}, {1, 2, 3}, {0, 3, 2}, {0, 2, 1}};
  std::vector<int> tetraPos(2), facePos(2);

  std::vector<std::vector<std::vector<int> > > prismStruct(3, std::vector<std::vector<int> >(4, std::vector<int>(3)));
  for (int i=0; i<indexToEdgeID.size()*numLayers; i++) {
	 int ib = (Ordering == 0)*(i%lEdgeColumnShift) + (Ordering == 1)*(i/edgeLayerShift);
	 if(isBoundaryEdge[ib])
	 {
		 int il = (Ordering == 0)*(i/lEdgeColumnShift) + (Ordering == 1)*(i%edgeLayerShift);
		 int lBasalElemId = trianglesOnEdge[2*ib];
		 int basalElemId = indexToTriangleID[lBasalElemId];

		 //TODO: this could be done only in the first layer and then copied into the other layers
		 int prismMpasIds[3], prismGlobalIds[6];
		 int shift = il*vertexColumnShift;
		 for (int j = 0; j < 3; j++)
		 {
			 int mpasLowerId = vertexLayerShift * indexToMpasVertexID[verticesOnTria[3*lBasalElemId+j]];
			 int lowerId = shift+vertexLayerShift * indexToVertexID[verticesOnTria[3*lBasalElemId+j]];
			 prismMpasIds[j] = mpasLowerId;
			 prismGlobalIds[j] = lowerId;
			 prismGlobalIds[j + 3] = lowerId+vertexColumnShift;
		 }

		  tetrasFromPrismStructured (prismMpasIds, prismGlobalIds, tetrasLocalIdsOnPrism);


		for(int iTetra = 0; iTetra<3; iTetra++)
		  {
			 std::vector<std::vector<int> >& tetraStruct =prismStruct[iTetra];
			 stk::mesh::EntityId tetraPoints[4];
			 for(int j=0; j<4; j++)
			 {
                           tetraPoints[j] = tetrasLocalIdsOnPrism[iTetra][j]+1;
				// std::cout<< tetraPoints[j] << ", ";
			 }
			 for(int iFace=0; iFace<4; iFace++)
			 {
				 std::vector<int>&  face = tetraStruct[iFace];
				 for(int j=0; j<3; j++)
				 	 face[j] = tetraPoints[tetraSidePoints[iFace][j]];
			 }
		  }



		 int basalVertexId[2] = {indexToVertexID[verticesOnEdge[2*ib]]*vertexLayerShift, indexToVertexID[verticesOnEdge[2*ib+1]]*vertexLayerShift};
		 std::vector<int> bdPrismFaceIds(4);

		 bdPrismFaceIds[0] = indexToVertexID[verticesOnEdge[2*ib]]*vertexLayerShift+vertexColumnShift*il+1;
		 bdPrismFaceIds[1] = indexToVertexID[verticesOnEdge[2*ib+1]]*vertexLayerShift+vertexColumnShift*il+1;
		 bdPrismFaceIds[2] = bdPrismFaceIds[0]+vertexColumnShift;
		 bdPrismFaceIds[3] = bdPrismFaceIds[1]+vertexColumnShift;

		 //std::cout<< "bdPrismFaceIds: (" << bdPrismFaceIds[0] << ", " << bdPrismFaceIds[1] << ", " << bdPrismFaceIds[2] << ", " << bdPrismFaceIds[3] << ")"<<std::endl;



		 setBdFacesOnPrism (prismStruct, bdPrismFaceIds, tetraPos, facePos);

		 int basalEdgeId = indexToEdgeID[ib]*2*edgeLayerShift;
		 for(int k=0; k< tetraPos.size(); k++)
		 {
			 int iTetra = tetraPos[k];
			 int iFace = facePos[k];
			 stk::mesh::Entity elem = bulkData->get_entity(stk::topology::ELEMENT_RANK, il*elemColumnShift+elemLayerShift * basalElemId +iTetra+1);
			 std::vector<int>& faceIds = prismStruct[iTetra][iFace];
			 stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), edgeColumnShift*il+basalEdgeId+k+1, singlePartVec);
			 bulkData->declare_relation(elem, side,  iFace );
			 for(int j=0; j<3; j++)
			 {
				 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, faceIds[j]);
				 bulkData->declare_relation(side, node, j);
			 }
		 }
	 }
  }

  //then we store the lower and upper faces of prisms, which corresponds to triangles of the basal mesh

  edgeLayerShift = (Ordering == 0) ? 1 : numLayers+1;
  edgeColumnShift = 2*(elemColumnShift/3);

  singlePartVec[0] = ssPartVec["basalside"];

  int edgeOffset = 2*nGlobalEdges*numLayers;
  for (int i=0; i<indexToTriangleID.size(); i++)
  {
	  stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), indexToTriangleID[i]*edgeLayerShift+edgeOffset+1, singlePartVec);
	  stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  indexToTriangleID[i]*elemLayerShift+1);
	  bulkData->declare_relation(elem, side,  3);
	  for(int j=0; j<3; j++)
	  {
		 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, vertexLayerShift*indexToVertexID[verticesOnTria[3*i+j]]+1);
		 bulkData->declare_relation(side, node, j);
	  }
  }

  singlePartVec[0] = ssPartVec["upperside"];

  for (int i=0; i<indexToTriangleID.size(); i++)
  {
	stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), indexToTriangleID[i]*edgeLayerShift+numLayers*edgeColumnShift+edgeOffset+1, singlePartVec);
	stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  indexToTriangleID[i]*elemLayerShift+(numLayers-1)*elemColumnShift+1+2);
	bulkData->declare_relation(elem, side,  1);
	for(int j=0; j<3; j++)
	{
	  stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, vertexLayerShift*indexToVertexID[verticesOnTria[3*i+j]]+numLayers*vertexColumnShift+1);
	  bulkData->declare_relation(side, node, j);
	}
  }

  bulkData->modification_end();
}
void
Albany::MpasSTKMeshStruct::constructMesh(
                                               const Teuchos::RCP<const Epetra_Comm>& comm,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const Albany::AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const std::vector<int>& indexToVertexID, const std::vector<double>& verticesCoords, const std::vector<bool>& isVertexBoundary, int nGlobalVertices,
                                               const std::vector<int>& verticesOnTria,
                                               const std::vector<bool>& isBoundaryEdge, const std::vector<int>& trianglesOnEdge, const std::vector<int>& trianglesPositionsOnEdge,
                                               const std::vector<int>& verticesOnEdge,
                                               const std::vector<int>& indexToEdgeID, int nGlobalEdges,
                                               const std::vector<int>& indexToTriangleID,
                                               const unsigned int worksetSize,
                                               int numLayers, int Ordering)
{
	this->SetupFieldData(comm, neq_, req, sis, worksetSize);

    int elemColumnShift = (Ordering == 1) ? 1 : elem_map->NumGlobalElements()/numLayers;
    int lElemColumnShift = (Ordering == 1) ? 1 : indexToTriangleID.size();
    int elemLayerShift = (Ordering == 0) ? 1 : numLayers;

    int vertexColumnShift = (Ordering == 1) ? 1 : nGlobalVertices;
    int lVertexColumnShift = (Ordering == 1) ? 1 : indexToVertexID.size();
    int vertexLayerShift = (Ordering == 0) ? 1 : numLayers+1;

    int edgeColumnShift = (Ordering == 1) ? 1 : nGlobalEdges;
    int lEdgeColumnShift = (Ordering == 1) ? 1 : indexToEdgeID.size();
    int edgeLayerShift = (Ordering == 0) ? 1 : numLayers;


  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  std::cout << "elem_map # elments: " << elem_map->NumMyElements() << std::endl;
  unsigned int ebNo = 0; //element block #???

  singlePartVec[0] = nsPartVec["Bottom"];


  AbstractSTKFieldContainer::IntScalarFieldType* proc_rank_field = fieldContainer->getProcRankField();
  AbstractSTKFieldContainer::VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();
  stk::mesh::Field<double>* surfaceHeight_field = metaData->get_field<stk::mesh::Field<double> >(stk::topology::NODE_RANK, "surface_height");

  for(int i=0; i< (numLayers+1)*indexToVertexID.size(); i++)
  {
	  int ib = (Ordering == 0)*(i%lVertexColumnShift) + (Ordering == 1)*(i/vertexLayerShift);
	  int il = (Ordering == 0)*(i/lVertexColumnShift) + (Ordering == 1)*(i%vertexLayerShift);

	  stk::mesh::Entity node;
	  if(il == 0)
		  node = bulkData->declare_entity(stk::topology::NODE_RANK, il*vertexColumnShift+vertexLayerShift * indexToVertexID[ib]+1, singlePartVec);
	  else
		  node = bulkData->declare_entity(stk::topology::NODE_RANK, il*vertexColumnShift+vertexLayerShift * indexToVertexID[ib]+1, nodePartVec);
	  int numBdEdges(0);
	  for (int i=0; i<indexToEdgeID.size(); i++)
		  numBdEdges += isBoundaryEdge[i];


          double* coord = stk::mesh::field_data(*coordinates_field, node);
	  coord[0] = verticesCoords[3*ib];   coord[1] = verticesCoords[3*ib+1]; coord[2] = double(il)/numLayers;

	  double* sHeight;
	   sHeight = stk::mesh::field_data(*surfaceHeight_field, node);
	   sHeight[0] = 1.;
  }

  for (int i=0; i<elem_map->NumMyElements(); i++) {

	 int ib = (Ordering == 0)*(i%lElemColumnShift) + (Ordering == 1)*(i/elemLayerShift);
	 int il = (Ordering == 0)*(i/lElemColumnShift) + (Ordering == 1)*(i%elemLayerShift);

	 int shift = il*vertexColumnShift;

	 singlePartVec[0] = partVec[ebNo];
     stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_map->GID(i)+1, singlePartVec);

     for(int j=0; j<3; j++)
     {
    	 int lowerId = shift+vertexLayerShift * indexToVertexID[verticesOnTria[3*ib+j]]+1;
    	 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, lowerId);
    	 bulkData->declare_relation(elem, node, j);

    	 stk::mesh::Entity node_top = bulkData->get_entity(stk::topology::NODE_RANK, lowerId+vertexColumnShift);
    	 bulkData->declare_relation(elem, node_top, j+3);
     }

     int* p_rank = (int*)stk::mesh::field_data(*proc_rank_field, elem);
     p_rank[0] = comm->MyPID();
  }


  singlePartVec[0] = ssPartVec["lateralside"];

  //first we store the lateral faces of prisms, which corresponds to edges of the basal mesh

  for (int i=0; i<indexToEdgeID.size()*numLayers; i++) {
	 int ib = (Ordering == 0)*(i%lEdgeColumnShift) + (Ordering == 1)*(i/edgeLayerShift);
	 if(isBoundaryEdge[ib])
	 {
		 int il = (Ordering == 0)*(i/lEdgeColumnShift) + (Ordering == 1)*(i%edgeLayerShift);
		 int basalEdgeId = indexToEdgeID[ib]*edgeLayerShift;
		 int basalElemId = indexToTriangleID[trianglesOnEdge[2*ib]]*elemLayerShift;
		 int basalVertexId[2] = {indexToVertexID[verticesOnEdge[2*ib]]*vertexLayerShift, indexToVertexID[verticesOnEdge[2*ib+1]]*vertexLayerShift};
		 stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), edgeColumnShift*il+basalEdgeId+1, singlePartVec);
		 stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  basalElemId+elemColumnShift*il+1);
		 bulkData->declare_relation(elem, side,  trianglesPositionsOnEdge[2*ib] );
		 for(int j=0; j<2; j++)
		 {
			 stk::mesh::Entity nodeBottom = bulkData->get_entity(stk::topology::NODE_RANK, basalVertexId[j]+vertexColumnShift*il+1);
			 bulkData->declare_relation(side, nodeBottom, j);
			 stk::mesh::Entity nodeTop = bulkData->get_entity(stk::topology::NODE_RANK, basalVertexId[j]+vertexColumnShift*(il+1)+1);
			 bulkData->declare_relation(side, nodeTop, j+2);
		 }
	 }
  }

  //then we store the lower and upper faces of prisms, which corresponds to triangles of the basal mesh

  edgeLayerShift = (Ordering == 0) ? 1 : numLayers+1;
  edgeColumnShift = elemColumnShift;

  singlePartVec[0] = ssPartVec["basalside"];

  int edgeOffset = nGlobalEdges*numLayers;
  for (int i=0; i<indexToTriangleID.size(); i++)
  {
	  stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), indexToTriangleID[i]*edgeLayerShift+edgeOffset+1, singlePartVec);
	  stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  indexToTriangleID[i]*elemLayerShift+1);
	  bulkData->declare_relation(elem, side,  3);
	  for(int j=0; j<3; j++)
	  {
		 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, vertexLayerShift*indexToVertexID[verticesOnTria[3*i+j]]+1);
		 bulkData->declare_relation(side, node, j);
	  }
  }

  singlePartVec[0] = ssPartVec["upperside"];

  for (int i=0; i<indexToTriangleID.size(); i++)
  {
  	  stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), indexToTriangleID[i]*edgeLayerShift+numLayers*edgeColumnShift+edgeOffset+1, singlePartVec);
  	  stk::mesh::Entity elem  = bulkData->get_entity(stk::topology::ELEMENT_RANK,  indexToTriangleID[i]*elemLayerShift+(numLayers-1)*elemColumnShift+1);
  	  bulkData->declare_relation(elem, side,  4);
  	  for(int j=0; j<3; j++)
  	  {
  		 stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, vertexLayerShift*indexToVertexID[verticesOnTria[3*i+j]]+numLayers*vertexColumnShift+1);
  		 bulkData->declare_relation(side, node, j);
  	  }
  }

  bulkData->modification_end();
}
void Albany::ExtrudedSTKMeshStruct::setFieldAndBulkData(
    const Teuchos::RCP<const Teuchos_Comm>& comm,
    const Teuchos::RCP<Teuchos::ParameterList>& params,
    const unsigned int neq_,
    const AbstractFieldContainer::FieldContainerRequirements& req,
    const Teuchos::RCP<Albany::StateInfoStruct>& sis,
    const unsigned int worksetSize)
{
  int numLayers = params->get("NumLayers", 10);
  bool useGlimmerSpacing = params->get("Use Glimmer Spacing", false);
  GO maxGlobalElements2D = 0;
  GO maxGlobalVertices2dId = 0;
  GO numGlobalVertices2D = 0;
  GO maxGlobalEdges2D = 0;
  bool Ordering = params->get("Columnwise Ordering", false);
  bool isTetra = true;

  stk::mesh::BulkData& bulkData2D = *basalMeshStruct->bulkData;
  stk::mesh::MetaData& metaData2D = *basalMeshStruct->metaData; //bulkData2D.mesh_meta_data();

  std::vector<double> levelsNormalizedThickness(numLayers + 1), temperatureNormalizedZ, flowRateNormalizedZ;

  if(useGlimmerSpacing)
    for (int i = 0; i < numLayers+1; i++)
      levelsNormalizedThickness[numLayers-i] = 1.0- (1.0 - std::pow(double(i) / numLayers + 1.0, -2))/(1.0 - std::pow(2.0, -2));
  else  //uniform layers
    for (int i = 0; i < numLayers+1; i++)
      levelsNormalizedThickness[i] = double(i) / numLayers;

  Teuchos::ArrayRCP<double> layerThicknessRatio(numLayers), layersNormalizedThickness(numLayers);
  for (int i = 0; i < numLayers; i++) {
    layerThicknessRatio[i] = levelsNormalizedThickness[i+1]-levelsNormalizedThickness[i];
    layersNormalizedThickness[i] = 0.5*(levelsNormalizedThickness[i]+levelsNormalizedThickness[i+1]);
  }

  /*std::cout<< "Levels: ";
  for (int i = 0; i < numLayers+1; i++)
    std::cout<< levelsNormalizedThickness[i] << " ";
  std::cout<< "\n";*/

  stk::mesh::Selector select_owned_in_part = stk::mesh::Selector(metaData2D.universal_part()) & stk::mesh::Selector(metaData2D.locally_owned_part());

  stk::mesh::Selector select_overlap_in_part = stk::mesh::Selector(metaData2D.universal_part()) & (stk::mesh::Selector(metaData2D.locally_owned_part()) | stk::mesh::Selector(metaData2D.globally_shared_part()));

  stk::mesh::Selector select_edges = stk::mesh::Selector(*metaData2D.get_part("LateralSide")) & (stk::mesh::Selector(metaData2D.locally_owned_part()) | stk::mesh::Selector(metaData2D.globally_shared_part()));

  std::vector<stk::mesh::Entity> cells2D;
  stk::mesh::get_selected_entities(select_overlap_in_part, bulkData2D.buckets(stk::topology::ELEMENT_RANK), cells2D);

  std::vector<stk::mesh::Entity> nodes2D;
  stk::mesh::get_selected_entities(select_overlap_in_part, bulkData2D.buckets(stk::topology::NODE_RANK), nodes2D);

  std::vector<stk::mesh::Entity> edges2D;
  stk::mesh::get_selected_entities(select_edges, bulkData2D.buckets(metaData2D.side_rank()), edges2D);

  GO maxOwnedElements2D(0), maxOwnedNodes2D(0), maxOwnedSides2D(0), numOwnedNodes2D(0);
  for (int i = 0; i < cells2D.size(); i++)
    maxOwnedElements2D = std::max(maxOwnedElements2D, (GO) bulkData2D.identifier(cells2D[i]));
  for (int i = 0; i < nodes2D.size(); i++)
    maxOwnedNodes2D = std::max(maxOwnedNodes2D, (GO) bulkData2D.identifier(nodes2D[i]));
  for (int i = 0; i < edges2D.size(); i++)
    maxOwnedSides2D = std::max(maxOwnedSides2D, (GO) bulkData2D.identifier(edges2D[i]));
  numOwnedNodes2D = stk::mesh::count_selected_entities(select_owned_in_part, bulkData2D.buckets(stk::topology::NODE_RANK));


  //WARNING Currently GO == long int. For gcc compiler, long == long long, however this might not be true with other compilers.

  //comm->MaxAll(&maxOwnedElements2D, &maxGlobalElements2D, 1);
  Teuchos::reduceAll<int, GO>(*comm, Teuchos::REDUCE_MAX, maxOwnedElements2D, Teuchos::ptr(&maxGlobalElements2D));
  //comm->MaxAll(&maxOwnedNodes2D, &maxGlobalVertices2dId, 1);
  Teuchos::reduceAll<int, GO>(*comm, Teuchos::REDUCE_MAX, maxOwnedNodes2D, Teuchos::ptr(&maxGlobalVertices2dId));
  //comm->MaxAll(&maxOwnedSides2D, &maxGlobalEdges2D, 1);
  Teuchos::reduceAll<int, GO>(*comm, Teuchos::REDUCE_MAX, maxOwnedSides2D, Teuchos::ptr(&maxGlobalEdges2D));
  //comm->SumAll(&numOwnedNodes2D, &numGlobalVertices2D, 1);
  //The following should not be int int...
  Teuchos::reduceAll<int, GO>(*comm, Teuchos::REDUCE_SUM, 1, &numOwnedNodes2D, &numGlobalVertices2D);

  if (comm->getRank() == 0) std::cout << "Importing ascii files ...";

  //std::cout << "Num Global Elements: " << maxGlobalElements2D<< " " << maxGlobalVertices2dId<< " " << maxGlobalEdges2D << std::endl;

  Teuchos::Array<GO> indices(nodes2D.size());
  for (int i = 0; i < nodes2D.size(); ++i)
    indices[i] = bulkData2D.identifier(nodes2D[i]) - 1;

  Teuchos::RCP<const Tpetra_Map>
    nodes_map = Tpetra::createNonContigMapWithNode<LO, GO> (
      indices(), comm, KokkosClassic::Details::getNode<KokkosNode>());
  int numMyElements = (comm->getRank() == 0) ? numGlobalVertices2D : 0;
  //Teuchos::RCP<const Tpetra_Map> serial_nodes_map = Tpetra::createUniformContigMap<LO, GO>(numMyElements, comm);
  Teuchos::RCP<const Tpetra_Map> serial_nodes_map = Teuchos::rcp(new const Tpetra_Map(INVALID, numMyElements, 0, comm));
  Teuchos::RCP<Tpetra_Import> importOperator = Teuchos::rcp(new Tpetra_Import(serial_nodes_map, nodes_map));

  Teuchos::RCP<Tpetra_Vector> temp = Teuchos::rcp(new Tpetra_Vector(serial_nodes_map));
  Teuchos::RCP<Tpetra_Vector> sHeightVec;
  Teuchos::RCP<Tpetra_Vector> thickVec;
  Teuchos::RCP<Tpetra_Vector> bTopographyVec;
  Teuchos::RCP<Tpetra_Vector> bFrictionVec;
  Teuchos::RCP<Tpetra_MultiVector> temperatureVecInterp;
  Teuchos::RCP<Tpetra_MultiVector> flowRateVecInterp;
  Teuchos::RCP<Tpetra_MultiVector> sVelocityVec;
  Teuchos::RCP<Tpetra_MultiVector> velocityRMSVec;



  bool hasSurface_height =  std::find(req.begin(), req.end(), "surface_height") != req.end();

  {
    sHeightVec = Teuchos::rcp(new Tpetra_Vector(nodes_map));
    std::string fname = params->get<std::string>("Surface Height File Name", "surface_height.ascii");
    read2DFileSerial(fname, temp, comm);
    sHeightVec->doImport(*temp, *importOperator, Tpetra::INSERT);
  }
  Teuchos::ArrayRCP<const ST> sHeightVec_constView = sHeightVec->get1dView();


  bool hasThickness =  std::find(req.begin(), req.end(), "thickness") != req.end();

  {
    std::string fname = params->get<std::string>("Thickness File Name", "thickness.ascii");
    read2DFileSerial(fname, temp, comm);
    thickVec = Teuchos::rcp(new Tpetra_Vector(nodes_map));
    thickVec->doImport(*temp, *importOperator, Tpetra::INSERT);
  }
  Teuchos::ArrayRCP<const ST> thickVec_constView = thickVec->get1dView();

  bool hasBed_topography =  std::find(req.begin(), req.end(), "bed_topography") != req.end();
  {
    std::string fname = params->get<std::string>("Bed Topography File Name", "bed_topography.ascii");
    read2DFileSerial(fname, temp, comm);
    bTopographyVec = Teuchos::rcp(new Tpetra_Vector(nodes_map));
    bTopographyVec->doImport(*temp, *importOperator, Tpetra::INSERT);
  }
  Teuchos::ArrayRCP<const ST> bTopographyVec_constView = bTopographyVec->get1dView();


  bool hasBasal_friction = std::find(req.begin(), req.end(), "basal_friction") != req.end();
  if(hasBasal_friction)
  {
    bFrictionVec = Teuchos::rcp(new Tpetra_Vector(nodes_map));

    if (params->isParameter("Basal Friction File Name"))
    {
      std::string fname = params->get<std::string>("Basal Friction File Name", "basal_friction.ascii");
      read2DFileSerial(fname, temp, comm);
      bFrictionVec->doImport(*temp, *importOperator, Tpetra::INSERT);
    }
    else
    {
      // Try to load it from the 2D mesh
      Albany::AbstractSTKFieldContainer::ScalarFieldType* field = 0;
      field = metaData2D.get_field<Albany::AbstractSTKFieldContainer::ScalarFieldType>(stk::topology::NODE_RANK, "basal_friction");
      if (field!=0)
      {
        Teuchos::ArrayRCP<ST> bFrictionVec_view = bFrictionVec->get1dViewNonConst();

        stk::mesh::Entity node;
        stk::mesh::EntityId nodeId;
        int lid;
        double* values;

        //Now we have to stuff the vector in the mesh data
        for (int i(0); i<nodes2D.size(); ++i)
        {
          nodeId = bulkData2D.identifier(nodes2D[i]) - 1;
          lid    = nodes_map->getLocalElement((GO)(nodeId));

          values = stk::mesh::field_data(*field, nodes2D[i]);
          bFrictionVec_view[lid] = values[0];
        }
      }
      else
      {
        // We use a zero vector, but we issue a warning. Just in case the user forgot to setup something
        std::cout << "No file name specified for 'basal_friction', and no field retrieved from the mesh. Using a zero vector.\n";
      }
    }
  }

  bool hasFlowRate = true;//std::find(req.begin(), req.end(), "flowRate") != req.end();
  if(hasFlowRate) {
    Teuchos::RCP<Tpetra_MultiVector> flowRateVec;
    flowRateVecInterp = Teuchos::rcp(new Tpetra_MultiVector(nodes_map, numLayers));
    std::string fname = params->get<std::string>("Flow Rate File Name", "flow_rate.ascii");
    int err = readFileSerial(fname, serial_nodes_map, nodes_map, importOperator, flowRateVec, flowRateNormalizedZ, comm);

    if(err == 0) {
      int il0, il1, verticalTSize(flowRateVec->getNumVectors());
      double h0(0.0);

      for (int il = 0; il < numLayers; il++) {
        if (layersNormalizedThickness[il] <= flowRateNormalizedZ[0]) {
          il0 = 0;
          il1 = 0;
          h0 = 1.0;
        }

        else if (layersNormalizedThickness[il] >= flowRateNormalizedZ[verticalTSize - 1]) {
          il0 = verticalTSize - 1;
          il1 = verticalTSize - 1;
          h0 = 0.0;
        }

        else {
          int k = 0;
          while (layersNormalizedThickness[il] > flowRateNormalizedZ[++k])
            ;
          il0 = k - 1;
          il1 = k;
          h0 = (flowRateNormalizedZ[il1] - layersNormalizedThickness[il]) / (flowRateNormalizedZ[il1] - flowRateNormalizedZ[il0]);
        }
        Teuchos::ArrayRCP<ST> flowRateVecInterp_nonConstView = flowRateVecInterp->getVectorNonConst(il)->get1dViewNonConst();
        Teuchos::ArrayRCP<const ST> flowRateVec_constView_il0 = flowRateVec->getVectorNonConst(il0)->get1dView();
        Teuchos::ArrayRCP<const ST> flowRateVec_constView_il1 = flowRateVec->getVectorNonConst(il1)->get1dView();

        for (int i = 0; i < nodes_map->getNodeNumElements(); i++)
          flowRateVecInterp_nonConstView[i] = h0 * flowRateVec_constView_il0[i] + (1.0 - h0) * flowRateVec_constView_il1[i];
      }
    }
    else hasFlowRate=false;
  }

  bool hasTemperature = std::find(req.begin(), req.end(), "temperature") != req.end();
  if(hasTemperature) {
    Teuchos::RCP<Tpetra_MultiVector> temperatureVec;
    temperatureVecInterp = Teuchos::rcp(new Tpetra_MultiVector(nodes_map, numLayers + 1));
    std::string fname = params->get<std::string>("Temperature File Name", "temperature.ascii");
    int err = readFileSerial(fname, serial_nodes_map, nodes_map, importOperator, temperatureVec, temperatureNormalizedZ, comm);

    if(err == 0) {
      int il0, il1, verticalTSize(temperatureVec->getNumVectors());
      double h0(0.0);

      for (int il = 0; il < numLayers + 1; il++) {
        if (levelsNormalizedThickness[il] <= temperatureNormalizedZ[0]) {
          il0 = 0;
          il1 = 0;
          h0 = 1.0;
        }

        else if (levelsNormalizedThickness[il] >= temperatureNormalizedZ[verticalTSize - 1]) {
          il0 = verticalTSize - 1;
          il1 = verticalTSize - 1;
          h0 = 0.0;
        }

        else {
          int k = 0;
          while (levelsNormalizedThickness[il] > temperatureNormalizedZ[++k])
            ;
          il0 = k - 1;
          il1 = k;
          h0 = (temperatureNormalizedZ[il1] - levelsNormalizedThickness[il]) / (temperatureNormalizedZ[il1] - temperatureNormalizedZ[il0]);
        }
        Teuchos::ArrayRCP<ST> temperatureVecInterp_nonConstView = temperatureVecInterp->getVectorNonConst(il)->get1dViewNonConst();
        Teuchos::ArrayRCP<const ST> temperatureVec_constView_il0 = temperatureVec->getVectorNonConst(il0)->get1dView();
        Teuchos::ArrayRCP<const ST> temperatureVec_constView_il1 = temperatureVec->getVectorNonConst(il1)->get1dView();

        for (int i = 0; i < nodes_map->getNodeNumElements(); i++)
          temperatureVecInterp_nonConstView[i] = h0 * temperatureVec_constView_il0[i] + (1.0 - h0) * temperatureVec_constView_il1[i];
      }
    }
    else hasTemperature = false;
  }

  Tpetra_MultiVector tempSV(serial_nodes_map,neq_);

  bool hasSurfaceVelocity = std::find(req.begin(), req.end(), "surface_velocity") != req.end();
  if(hasSurfaceVelocity) {
    std::string fname = params->get<std::string>("Surface Velocity File Name", "surface_velocity.ascii");
    readFileSerial(fname, tempSV, comm);
    sVelocityVec = Teuchos::rcp(new Tpetra_MultiVector (nodes_map, neq_));
    sVelocityVec->doImport(tempSV, *importOperator, Tpetra::INSERT);
  }

  bool hasSurfaceVelocityRMS = std::find(req.begin(), req.end(), "surface_velocity_rms") != req.end();
  if(hasSurfaceVelocityRMS) {
    std::string fname = params->get<std::string>("Surface Velocity RMS File Name", "velocity_RMS.ascii");
    readFileSerial(fname, tempSV, comm);
    velocityRMSVec = Teuchos::rcp(new Tpetra_MultiVector (nodes_map, neq_));
    velocityRMSVec->doImport(tempSV, *importOperator, Tpetra::INSERT);
  }

  if (comm->getRank() == 0) std::cout << " done." << std::endl;

  GO elemColumnShift = (Ordering == 1) ? 1 : maxGlobalElements2D;
  int lElemColumnShift = (Ordering == 1) ? 1 : cells2D.size();
  int elemLayerShift = (Ordering == 0) ? 1 : numLayers;

  GO vertexColumnShift = (Ordering == 1) ? 1 : maxGlobalVertices2dId;
  int lVertexColumnShift = (Ordering == 1) ? 1 : nodes2D.size();
  int vertexLayerShift = (Ordering == 0) ? 1 : numLayers + 1;

  GO edgeColumnShift = (Ordering == 1) ? 1 : maxGlobalEdges2D;
  int lEdgeColumnShift = (Ordering == 1) ? 1 : edges2D.size();
  int edgeLayerShift = (Ordering == 0) ? 1 : numLayers;

  this->layered_mesh_numbering = (Ordering==0) ?
      Teuchos::rcp(new LayeredMeshNumbering<LO>(lVertexColumnShift,Ordering,layerThicknessRatio)):
      Teuchos::rcp(new LayeredMeshNumbering<LO>(vertexLayerShift,Ordering,layerThicknessRatio));

  this->SetupFieldData(comm, neq_, req, sis, worksetSize);

  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  unsigned int ebNo = 0; //element block #???

  singlePartVec[0] = nsPartVec["bottom"];

  typedef AbstractSTKFieldContainer::ScalarFieldType ScalarFieldType;
  typedef AbstractSTKFieldContainer::VectorFieldType VectorFieldType;
  typedef AbstractSTKFieldContainer::QPScalarFieldType ElemScalarFieldType;

  AbstractSTKFieldContainer::IntScalarFieldType* proc_rank_field = fieldContainer->getProcRankField();
  VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();
  stk::mesh::FieldBase const* coordinates_field2d = metaData2D.coordinate_field();
  VectorFieldType* surface_velocity_field = metaData->get_field<VectorFieldType>(stk::topology::NODE_RANK, "surface_velocity");
  VectorFieldType* surface_velocity_RMS_field = metaData->get_field<VectorFieldType>(stk::topology::NODE_RANK, "surface_velocity_rms");
  ScalarFieldType* surface_height_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "surface_height");
  ScalarFieldType* thickness_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "thickness");
  ScalarFieldType* bed_topography_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "bed_topography");
  ScalarFieldType* basal_friction_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "basal_friction");
  ElemScalarFieldType* temperature_field = metaData->get_field<ElemScalarFieldType>(stk::topology::ELEMENT_RANK, "temperature");
  ElemScalarFieldType* flowRate_field = metaData->get_field<ElemScalarFieldType>(stk::topology::ELEMENT_RANK, "flow_factor");

  std::vector<GO> prismMpasIds(NumBaseElemeNodes), prismGlobalIds(2 * NumBaseElemeNodes);

  for (int i = 0; i < (numLayers + 1) * nodes2D.size(); i++) {
    int ib = (Ordering == 0) * (i % lVertexColumnShift) + (Ordering == 1) * (i / vertexLayerShift);
    int il = (Ordering == 0) * (i / lVertexColumnShift) + (Ordering == 1) * (i % vertexLayerShift);
    stk::mesh::Entity node;
    stk::mesh::Entity node2d = nodes2D[ib];
    stk::mesh::EntityId node2dId = bulkData2D.identifier(node2d) - 1;
    if (il == 0)
      node = bulkData->declare_entity(stk::topology::NODE_RANK, il * vertexColumnShift + vertexLayerShift * node2dId + 1, singlePartVec);
    else
      node = bulkData->declare_entity(stk::topology::NODE_RANK, il * vertexColumnShift + vertexLayerShift * node2dId + 1, nodePartVec);

    std::vector<int> sharing_procs;
    bulkData2D.comm_shared_procs( bulkData2D.entity_key(node2d), sharing_procs );
    for(int iproc=0; iproc<sharing_procs.size(); ++iproc)
      bulkData->add_node_sharing(node, sharing_procs[iproc]);


    double* coord = stk::mesh::field_data(*coordinates_field, node);
    double const* coord2d = (double const*) stk::mesh::field_data(*coordinates_field2d, node2d);
    coord[0] = coord2d[0];
    coord[1] = coord2d[1];

    int lid = nodes_map->getLocalElement((GO)(node2dId));
    coord[2] = sHeightVec_constView[lid] - thickVec_constView[lid] * (1. - levelsNormalizedThickness[il]);

    if(hasSurface_height && surface_height_field) {
      double* sHeight = stk::mesh::field_data(*surface_height_field, node);
      sHeight[0] = sHeightVec_constView[lid];
    }

    if(hasThickness && thickness_field) {
      double* thick = stk::mesh::field_data(*thickness_field, node);
      thick[0] = thickVec_constView[lid];
    }

    if(hasBed_topography && bed_topography_field) {
      double* bedTopo = stk::mesh::field_data(*bed_topography_field, node);
      bedTopo[0] = bTopographyVec_constView[lid];
    }

    if(surface_velocity_field) {
      double* sVelocity = stk::mesh::field_data(*surface_velocity_field, node);
      Teuchos::ArrayRCP<const ST> sVelocityVec_constView_0 = sVelocityVec->getVectorNonConst(0)->get1dView();
      Teuchos::ArrayRCP<const ST> sVelocityVec_constView_1 = sVelocityVec->getVectorNonConst(1)->get1dView();
      sVelocity[0] = sVelocityVec_constView_0[lid];
      sVelocity[1] = sVelocityVec_constView_1[lid];
    }

    if(surface_velocity_RMS_field) {
      double* velocityRMS = stk::mesh::field_data(*surface_velocity_RMS_field, node);
      Teuchos::ArrayRCP<const ST> velocityRMSVec_constView_0 = velocityRMSVec->getVectorNonConst(0)->get1dView();
      Teuchos::ArrayRCP<const ST> velocityRMSVec_constView_1 = velocityRMSVec->getVectorNonConst(1)->get1dView();
      velocityRMS[0] = velocityRMSVec_constView_0[lid];
      velocityRMS[1] = velocityRMSVec_constView_1[lid];

    }

    if(hasBasal_friction && basal_friction_field) {
      double* bFriction = stk::mesh::field_data(*basal_friction_field, node);
      bFriction[0] = bFrictionVec->get1dView()[lid];
    }
  }

  GO tetrasLocalIdsOnPrism[3][4];

  for (int i = 0; i < cells2D.size() * numLayers; i++) {

    int ib = (Ordering == 0) * (i % lElemColumnShift) + (Ordering == 1) * (i / elemLayerShift);
    int il = (Ordering == 0) * (i / lElemColumnShift) + (Ordering == 1) * (i % elemLayerShift);

    int shift = il * vertexColumnShift;

    singlePartVec[0] = partVec[ebNo];

    //TODO: this could be done only in the first layer and then copied into the other layers

    stk::mesh::Entity const* rel = bulkData2D.begin_nodes(cells2D[ib]);
    double tempOnPrism = 0; //Set temperature constant on each prism/Hexa
    Teuchos::ArrayRCP<const ST> temperatureVecInterp_constView_il,  temperatureVecInterp_constView_ilplus1;
    if(hasTemperature) {
      temperatureVecInterp_constView_il = temperatureVecInterp->getVectorNonConst(il)->get1dView();
      temperatureVecInterp_constView_ilplus1 = temperatureVecInterp->getVectorNonConst(il + 1)->get1dView();
    }

    double flowRateOnPrism = 0; //Set temperature constant on each prism/Hexa
    Teuchos::ArrayRCP<const ST> flowRateVecInterp_constView_il, flowRateVecInterp_constView_ilplus1;
    if(hasFlowRate) {
      flowRateVecInterp_constView_il = flowRateVecInterp->getVectorNonConst(il)->get1dView();
    }
    for (int j = 0; j < NumBaseElemeNodes; j++) {
      stk::mesh::EntityId node2dId = bulkData2D.identifier(rel[j]) - 1;
      int node2dLId = nodes_map->getLocalElement((GO)node2dId);
      stk::mesh::EntityId mpasLowerId = vertexLayerShift * node2dId;
      stk::mesh::EntityId lowerId = shift + vertexLayerShift * node2dId;
      prismMpasIds[j] = mpasLowerId;
      prismGlobalIds[j] = lowerId;
      prismGlobalIds[j + NumBaseElemeNodes] = lowerId + vertexColumnShift;
      if(hasTemperature)
        tempOnPrism += 1. / NumBaseElemeNodes / 2. * (temperatureVecInterp_constView_il[node2dLId] + temperatureVecInterp_constView_ilplus1[node2dLId]);
      if(hasFlowRate)
        flowRateOnPrism += 1. / NumBaseElemeNodes  * flowRateVecInterp_constView_il[node2dLId];
    }

    switch (ElemShape) {
    case Tetrahedron: {
      tetrasFromPrismStructured(&prismMpasIds[0], &prismGlobalIds[0], tetrasLocalIdsOnPrism);

      stk::mesh::EntityId prismId = il * elemColumnShift + elemLayerShift * (bulkData2D.identifier(cells2D[ib]) - 1);
      for (int iTetra = 0; iTetra < 3; iTetra++) {
        stk::mesh::Entity elem = bulkData->declare_entity(stk::topology::ELEMENT_RANK, 3 * prismId + iTetra + 1, singlePartVec);
        for (int j = 0; j < 4; j++) {
          stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, tetrasLocalIdsOnPrism[iTetra][j] + 1);
          bulkData->declare_relation(elem, node, j);
        }
        int* p_rank = (int*) stk::mesh::field_data(*proc_rank_field, elem);
        p_rank[0] = comm->getRank();
        if(hasFlowRate && flowRate_field) {
          double* flowRate = stk::mesh::field_data(*flowRate_field, elem);
          flowRate[0] = flowRateOnPrism;
        }
        if(hasTemperature && temperature_field) {
          double* temperature = stk::mesh::field_data(*temperature_field, elem);
          temperature[0] = tempOnPrism;
        }
      }
    }
      break;
    case Wedge:
    case Hexahedron: {
      stk::mesh::EntityId prismId = il * elemColumnShift + elemLayerShift * (bulkData2D.identifier(cells2D[ib]) - 1);
      stk::mesh::Entity elem = bulkData->declare_entity(stk::topology::ELEMENT_RANK, prismId + 1, singlePartVec);
      for (int j = 0; j < 2 * NumBaseElemeNodes; j++) {
        stk::mesh::Entity node = bulkData->get_entity(stk::topology::NODE_RANK, prismGlobalIds[j] + 1);
        bulkData->declare_relation(elem, node, j);
      }
      int* p_rank = (int*) stk::mesh::field_data(*proc_rank_field, elem);
      p_rank[0] = comm->getRank();
      if(hasFlowRate && flowRate_field) {
        double* flowRate = stk::mesh::field_data(*flowRate_field, elem);
        flowRate[0] = flowRateOnPrism;
      }
      if(hasTemperature && temperature_field) {
        double* temperature = stk::mesh::field_data(*temperature_field, elem);
        temperature[0] = tempOnPrism;
      }
    }
    }
  }

  int numSubelemOnPrism, numBasalSidePoints;
  int basalSideLID, upperSideLID;

  switch (ElemShape) {
  case Tetrahedron:
    numSubelemOnPrism = 3;
    numBasalSidePoints = 3;
    basalSideLID = 3;  //depends on how the tetrahedron is located in the Prism, see tetraFaceIdOnPrismFaceId below.
    upperSideLID = 1;
    break;
  case Wedge:
    numSubelemOnPrism = 1;
    numBasalSidePoints = 3;
    basalSideLID = 3;  //depends on how the tetrahedron is located in the Prism.
    upperSideLID = 4;
    break;
  case Hexahedron:
    numSubelemOnPrism = 1;
    numBasalSidePoints = 4;
    basalSideLID = 4;  //depends on how the tetrahedron is located in the Prism.
    upperSideLID = 5;
    break;
  }

  singlePartVec[0] = ssPartVec["lateralside"];

  //The following two arrays have being computed offline using the computeMap function in .hpp file.

  //tetraFaceIdOnPrismFaceId[ minIndex ][ PrismFaceID ]
  int tetraFaceIdOnPrismFaceId[6][5] = {{0, 1, 2, 3, 1}, {2, 0, 1, 3, 1}, {1, 2, 0, 3, 1}, {2, 1, 0, 1 ,3}, {0, 2, 1, 1, 3}, {1, 0, 2, 1, 3}};

  //tetraAdjacentToPrismLateralFace[ minIndex ][ prismType ][ PrismFaceID ][ iTetra ]. There are to Terahedra adjacent to a Prism face. iTetra in {0,1}
  int tetraAdjacentToPrismLateralFace[6][2][3][2] = { { { { 1, 2 }, { 0, 1 }, { 0, 2 } }, { { 0, 2 }, { 0, 1 }, { 1, 2 } } },
                                                      { { { 0, 2 }, { 1, 2 }, { 0, 1 } }, { { 1, 2 }, { 0, 2 }, { 0, 1 } } },
                                                      { { { 0, 1 }, { 0, 2 }, { 1, 2 } }, { { 0, 1 }, { 1, 2 }, { 0, 2 } } },
                                                      { { { 0, 2 }, { 0, 1 }, { 1, 2 } }, { { 1, 2 }, { 0, 1 }, { 0, 2 } } },
                                                      { { { 1, 2 }, { 0, 2 }, { 0, 1 } }, { { 0, 2 }, { 1, 2 }, { 0, 1 } } },
                                                      { { { 0, 1 }, { 1, 2 }, { 0, 2 } }, { { 0, 1 }, { 0, 2 }, { 1, 2 } } } };

  for (int i = 0; i < edges2D.size() * numLayers; i++) {
    int ib = (Ordering == 0) * (i % lEdgeColumnShift) + (Ordering == 1) * (i / edgeLayerShift);
    // if(!isBoundaryEdge[ib]) continue; //WARNING: assuming that all the edges stored are boundary edges!!

    stk::mesh::Entity edge2d = edges2D[ib];
    stk::mesh::Entity const* rel = bulkData2D.begin_elements(edge2d);
    stk::mesh::ConnectivityOrdinal const* ordinals = bulkData2D.begin_element_ordinals(edge2d);

    int il = (Ordering == 0) * (i / lEdgeColumnShift) + (Ordering == 1) * (i % edgeLayerShift);
    stk::mesh::Entity elem2d = rel[0];
    stk::mesh::EntityId edgeLID = ordinals[0]; //bulkData2D.identifier(rel[0]);

    stk::mesh::EntityId basalElemId = bulkData2D.identifier(elem2d) - 1;
    stk::mesh::EntityId Edge2dId = bulkData2D.identifier(edge2d) - 1;
    switch (ElemShape) {
    case Tetrahedron: {
      rel = bulkData2D.begin_nodes(elem2d);
      for (int j = 0; j < NumBaseElemeNodes; j++) {
        stk::mesh::EntityId node2dId = bulkData2D.identifier(rel[j]) - 1;
        prismMpasIds[j] = vertexLayerShift * node2dId;
      }
      int minIndex;
      int pType = prismType(&prismMpasIds[0], minIndex);
      stk::mesh::EntityId tetraId = 3 * il * elemColumnShift + 3 * elemLayerShift * basalElemId;

      stk::mesh::Entity elem0 = bulkData->get_entity(stk::topology::ELEMENT_RANK, tetraId + tetraAdjacentToPrismLateralFace[minIndex][pType][edgeLID][0] + 1);
      stk::mesh::Entity elem1 = bulkData->get_entity(stk::topology::ELEMENT_RANK, tetraId + tetraAdjacentToPrismLateralFace[minIndex][pType][edgeLID][1] + 1);

      stk::mesh::Entity side0 = bulkData->declare_entity(metaData->side_rank(), 2 * edgeColumnShift * il +  2 * Edge2dId * edgeLayerShift + 1, singlePartVec);
      stk::mesh::Entity side1 = bulkData->declare_entity(metaData->side_rank(), 2 * edgeColumnShift * il +  2 * Edge2dId * edgeLayerShift + 1 + 1, singlePartVec);

      bulkData->declare_relation(elem0, side0, tetraFaceIdOnPrismFaceId[minIndex][edgeLID]);
      bulkData->declare_relation(elem1, side1, tetraFaceIdOnPrismFaceId[minIndex][edgeLID]);

      stk::mesh::Entity const* rel_elemNodes0 = bulkData->begin_nodes(elem0);
      stk::mesh::Entity const* rel_elemNodes1 = bulkData->begin_nodes(elem1);
      for (int j = 0; j < 3; j++) {
     //   std::cout << j <<", " << edgeLID << ", " << minIndex << ", " << tetraFaceIdOnPrismFaceId[minIndex][edgeLID] << ","  << std::endl;
        stk::mesh::Entity node0 = rel_elemNodes0[this->meshSpecs[0]->ctd.side[tetraFaceIdOnPrismFaceId[minIndex][edgeLID]].node[j]];
        bulkData->declare_relation(side0, node0, j);
        stk::mesh::Entity node1 = rel_elemNodes1[this->meshSpecs[0]->ctd.side[tetraFaceIdOnPrismFaceId[minIndex][edgeLID]].node[j]];
        bulkData->declare_relation(side1, node1, j);
      }
    }

      break;
    case Wedge:
    case Hexahedron: {
      stk::mesh::EntityId prismId = il * elemColumnShift + elemLayerShift * basalElemId;
      stk::mesh::Entity elem = bulkData->get_entity(stk::topology::ELEMENT_RANK, prismId + 1);
      stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), edgeColumnShift * il +Edge2dId * edgeLayerShift + 1, singlePartVec);
      bulkData->declare_relation(elem, side, edgeLID);

      stk::mesh::Entity const* rel_elemNodes = bulkData->begin_nodes(elem);
      for (int j = 0; j < 4; j++) {
        stk::mesh::Entity node = rel_elemNodes[this->meshSpecs[0]->ctd.side[edgeLID].node[j]];
        bulkData->declare_relation(side, node, j);
      }
    }
    break;
    }
  }

  //then we store the lower and upper faces of prisms, which corresponds to triangles of the basal mesh
  edgeLayerShift = (Ordering == 0) ? 1 : numLayers + 1;
  edgeColumnShift = elemColumnShift;

  singlePartVec[0] = ssPartVec["basalside"];


  GO edgeOffset = maxGlobalEdges2D * numLayers;
  if(ElemShape == Tetrahedron) edgeOffset *= 2;

  for (int i = 0; i < cells2D.size(); i++) {
    stk::mesh::Entity elem2d = cells2D[i];
    stk::mesh::EntityId elem2d_id = bulkData2D.identifier(elem2d) - 1;
    stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), elem2d_id + edgeOffset + 1, singlePartVec);
    stk::mesh::Entity elem = bulkData->get_entity(stk::topology::ELEMENT_RANK, elem2d_id * numSubelemOnPrism * elemLayerShift + 1);
    bulkData->declare_relation(elem, side, basalSideLID);

    stk::mesh::Entity const* rel_elemNodes = bulkData->begin_nodes(elem);
    for (int j = 0; j < numBasalSidePoints; j++) {
      stk::mesh::Entity node = rel_elemNodes[this->meshSpecs[0]->ctd.side[basalSideLID].node[j]];
      bulkData->declare_relation(side, node, j);
    }
  }

  singlePartVec[0] = ssPartVec["upperside"];

  edgeOffset += maxGlobalElements2D;

  for (int i = 0; i < cells2D.size(); i++) {
    stk::mesh::Entity elem2d = cells2D[i];
    stk::mesh::EntityId elem2d_id = bulkData2D.identifier(elem2d) - 1;
    stk::mesh::Entity side = bulkData->declare_entity(metaData->side_rank(), elem2d_id  + edgeOffset + 1, singlePartVec);
    stk::mesh::Entity elem = bulkData->get_entity(stk::topology::ELEMENT_RANK, elem2d_id * numSubelemOnPrism * elemLayerShift + (numLayers - 1) * numSubelemOnPrism * elemColumnShift + 1 + (numSubelemOnPrism - 1));
    bulkData->declare_relation(elem, side, upperSideLID);

    stk::mesh::Entity const* rel_elemNodes = bulkData->begin_nodes(elem);
    for (int j = 0; j < numBasalSidePoints; j++) {
      stk::mesh::Entity node = rel_elemNodes[this->meshSpecs[0]->ctd.side[upperSideLID].node[j]];
      bulkData->declare_relation(side, node, j);
    }
  }
  //Albany::fix_node_sharing(*bulkData);
  bulkData->modification_end();

  if (params->get("Export 2D Data",false))
  {
    // We export the basal mesh in GMSH format
    std::ofstream ofile;
    ofile.open (params->get("GMSH 2D Output File Name","basal_mesh.msh"));
    TEUCHOS_TEST_FOR_EXCEPTION (!ofile.is_open(), std::logic_error, "Error! Cannot open file 'basal_mesh.msh'.\n");

    // Preamble
    ofile << "$MeshFormat\n"
          << "2.2 0 8\n"
          << "$EndMeshFormat\n";

    // Nodes
    ofile << "$Nodes\n" << nodes2D.size() << "\n";
    stk::mesh::Entity node2d;
    stk::mesh::EntityId nodeId;
    for (int i(0); i<nodes2D.size(); ++i)
    {
      node2d = bulkData2D.get_entity(stk::topology::NODE_RANK, i + 1);
      nodeId = bulkData2D.identifier(nodes2D[i]);

      double const* coord2d = (double const*) stk::mesh::field_data(*coordinates_field2d, node2d);

      ofile << nodeId << " " << coord2d[0] << " " << coord2d[1] << " " << 0. << "\n";
    }
    ofile << "$EndNodes\n";

    // Mesh Elements (including edges)
    ofile << "$Elements\n";
    ofile << edges2D.size()+cells2D.size() << "\n";

    int counter = 1;

    // edges
    for (int i(0); i<edges2D.size(); ++i)
    {
      stk::mesh::Entity const* rel = bulkData2D.begin_nodes(edges2D[i]);

      ofile << counter << " " << 1 << " " << 2 << " " << 30 << " " << 1;
      for (int j(0); j<2; ++j)
      {
        stk::mesh::EntityId node2dId = bulkData2D.identifier(rel[j]);
        ofile << " " << node2dId;
      }
      ofile << "\n";
      ++counter;
    }

    // elements
    for (int i(0); i<cells2D.size(); ++i)
    {
      stk::mesh::Entity const* rel = bulkData2D.begin_nodes(cells2D[i]);
      ofile << counter << " " << 2 << " " << 2 << " " << 100 << " " << 11;
      for (int j(0); j<3; ++j)
      {
        stk::mesh::EntityId node2dId = bulkData2D.identifier(rel[j]);
        ofile << " " << node2dId;
      }
      ofile << "\n";
      ++counter;
    }
    ofile << "$EndElements\n";

    ofile.close();
  }
}
void
Albany::AsciiSTKMeshStruct::setFieldAndBulkData(
                                               const Teuchos::RCP<const Epetra_Comm>& comm,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const unsigned int worksetSize)
{
  this->SetupFieldData(comm, neq_, req, sis, worksetSize);

  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  std::cout << "elem_map # elements: " << elem_map->NumMyElements() << std::endl; 
  std::cout << "node_map # elements: " << node_map->NumMyElements() << std::endl; 
  unsigned int ebNo = 0; //element block #??? 
  int sideID = 0;

  AbstractSTKFieldContainer::VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();
  AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = fieldContainer->getSurfaceHeightField();
  AbstractSTKFieldContainer::ScalarFieldType* flowFactor_field = fieldContainer->getFlowFactorField();
  AbstractSTKFieldContainer::ScalarFieldType* temperature_field = fieldContainer->getTemperatureField();
  AbstractSTKFieldContainer::ScalarFieldType* basal_friction_field = fieldContainer->getBasalFrictionField();

  if(!surfaceHeight_field) 
     have_sh = false;
  if(!flowFactor_field) 
     have_flwa = false;
  if(!temperature_field) 
     have_temp = false;
  if(!basal_friction_field) 
     have_beta = false;

  for (int i=0; i<elem_map->NumMyElements(); i++) {
     const unsigned int elem_GID = elem_map->GID(i);
     //std::cout << "elem_GID: " << elem_GID << std::endl; 
     stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
     singlePartVec[0] = partVec[ebNo];
     stk::mesh::Entity& elem  = bulkData->declare_entity(metaData->element_rank(), 1+elem_id, singlePartVec);
     //I am assuming the ASCII mesh is 1-based not 0-based, so no need to add 1 for STK mesh 
     stk::mesh::Entity& llnode = bulkData->declare_entity(metaData->node_rank(), eles[i][0], nodePartVec);
     stk::mesh::Entity& lrnode = bulkData->declare_entity(metaData->node_rank(), eles[i][1], nodePartVec);
     stk::mesh::Entity& urnode = bulkData->declare_entity(metaData->node_rank(), eles[i][2], nodePartVec);
     stk::mesh::Entity& ulnode = bulkData->declare_entity(metaData->node_rank(), eles[i][3], nodePartVec);
     stk::mesh::Entity& llnodeb = bulkData->declare_entity(metaData->node_rank(), eles[i][4], nodePartVec);
     stk::mesh::Entity& lrnodeb = bulkData->declare_entity(metaData->node_rank(), eles[i][5], nodePartVec);
     stk::mesh::Entity& urnodeb = bulkData->declare_entity(metaData->node_rank(), eles[i][6], nodePartVec);
     stk::mesh::Entity& ulnodeb = bulkData->declare_entity(metaData->node_rank(), eles[i][7], nodePartVec);
     bulkData->declare_relation(elem, llnode, 0);
     bulkData->declare_relation(elem, lrnode, 1);
     bulkData->declare_relation(elem, urnode, 2);
     bulkData->declare_relation(elem, ulnode, 3);
     bulkData->declare_relation(elem, llnodeb, 4);
     bulkData->declare_relation(elem, lrnodeb, 5);
     bulkData->declare_relation(elem, urnodeb, 6);
     bulkData->declare_relation(elem, ulnodeb, 7);
    

     double* coord;
     int node_GID;
     unsigned int node_LID;

     node_GID = eles[i][0]-1;
     node_LID = node_map->LID(node_GID);
     coord = stk::mesh::field_data(*coordinates_field, llnode);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     node_GID = eles[i][1]-1;
     node_LID = node_map->LID(node_GID);
     coord = stk::mesh::field_data(*coordinates_field, lrnode);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     node_GID = eles[i][2]-1;
     node_LID = node_map->LID(node_GID);
     coord = stk::mesh::field_data(*coordinates_field, urnode);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     node_GID = eles[i][3]-1;
     node_LID = node_map->LID(node_GID);
     coord = stk::mesh::field_data(*coordinates_field, ulnode);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     coord = stk::mesh::field_data(*coordinates_field, llnodeb);
     node_GID = eles[i][4]-1;
     node_LID = node_map->LID(node_GID);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     node_GID = eles[i][5]-1;
     node_LID = node_map->LID(node_GID);
     coord = stk::mesh::field_data(*coordinates_field, lrnodeb);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     coord = stk::mesh::field_data(*coordinates_field, urnodeb);
     node_GID = eles[i][6]-1;
     node_LID = node_map->LID(node_GID);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

     coord = stk::mesh::field_data(*coordinates_field, ulnodeb);
     node_GID = eles[i][7]-1;
     node_LID = node_map->LID(node_GID);
     coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];

#ifdef ALBANY_FELIX
     if (have_sh) {
       double* sHeight;
       sHeight = stk::mesh::field_data(*surfaceHeight_field, llnode);
       node_GID = eles[i][0]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, lrnode);
       node_GID = eles[i][1]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, urnode);
       node_GID = eles[i][2]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, ulnode);
       node_GID = eles[i][3]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, llnodeb);
       node_GID = eles[i][4]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, lrnodeb);
       node_GID = eles[i][5]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, urnodeb);
       node_GID = eles[i][6]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];

       sHeight = stk::mesh::field_data(*surfaceHeight_field, ulnodeb);
       node_GID = eles[i][7]-1;
       node_LID = node_map->LID(node_GID);
       sHeight[0] = sh[node_LID];
     }
     if (have_flwa) {
       double *flowFactor = stk::mesh::field_data(*flowFactor_field, elem); 
       //i is elem_LID (element local ID);
       //*out << "i: " << i <<", flwa: " << flwa[i] << std::endl;  
       flowFactor[0] = flwa[i]; 
     }
     if (have_temp) {
       double *temperature = stk::mesh::field_data(*temperature_field, elem); 
       //i is elem_LID (element local ID);
       //*out << "i: " << i <<", temp: " << temperature[i] << std::endl;  
       temperature[0] = temper[i]; 
     }
     if (have_beta) {
       double* bFriction; 
       bFriction = stk::mesh::field_data(*basal_friction_field, llnode);
       node_GID = eles[i][0]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, lrnode);
       node_GID = eles[i][1]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, urnode);
       node_GID = eles[i][2]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, ulnode);
       node_GID = eles[i][3]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, llnodeb);
       node_GID = eles[i][4]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, lrnodeb);
       node_GID = eles[i][5]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, urnodeb);
       node_GID = eles[i][6]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID];

       bFriction = stk::mesh::field_data(*basal_friction_field, ulnodeb);
       node_GID = eles[i][7]-1;
       node_LID = node_map->LID(node_GID);
       bFriction[0] = beta[node_LID]; 
       }
#endif

     // If first node has z=0 and there is no basal face file provided, identify it as a Basal SS
     if (have_bf == false) {
       std::cout <<"No bf file specified...  setting basal boundary to z=0 plane..." << std::endl; 
       if ( xyz[eles[i][0]][2] == 0.0) {
          //std::cout << "sideID: " << sideID << std::endl; 
          singlePartVec[0] = ssPartVec["Basal"];
          stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
          sideID++;

         stk::mesh::Entity& side  = bulkData->declare_entity(metaData->side_rank(), 1 + side_id, singlePartVec);
         bulkData->declare_relation(elem, side,  4 /*local side id*/);

         bulkData->declare_relation(side, llnode, 0);
         bulkData->declare_relation(side, ulnode, 3);
         bulkData->declare_relation(side, urnode, 2);
         bulkData->declare_relation(side, lrnode, 1);
       }
    }

    if (xyz[eles[i][0]-1][0] == 0.0) {
       singlePartVec[0] = nsPartVec["NodeSet0"];
       bulkData->change_entity_parts(llnode, singlePartVec); // node 0
       bulkData->change_entity_parts(ulnode, singlePartVec); // 3
       bulkData->change_entity_parts(llnodeb, singlePartVec); // 4
       bulkData->change_entity_parts(ulnodeb, singlePartVec); // 7
    }
    if (xyz[eles[i][1]-1][0] == 1.0) {
       singlePartVec[0] = nsPartVec["NodeSet1"];
       bulkData->change_entity_parts(lrnode, singlePartVec); // 1
       bulkData->change_entity_parts(urnode, singlePartVec); // 2
       bulkData->change_entity_parts(lrnodeb, singlePartVec); // 5
       bulkData->change_entity_parts(urnodeb, singlePartVec); // 6
    }
    if (xyz[eles[i][0]-1][1] == 0.0) {
       singlePartVec[0] = nsPartVec["NodeSet2"];
       bulkData->change_entity_parts(llnode, singlePartVec); // 0
       bulkData->change_entity_parts(lrnode, singlePartVec); // 1
       bulkData->change_entity_parts(llnodeb, singlePartVec); // 4
       bulkData->change_entity_parts(lrnodeb, singlePartVec); // 5
    }
    if (xyz[eles[i][2]-1][1] == 1.0) {
       singlePartVec[0] = nsPartVec["NodeSet3"];
       bulkData->change_entity_parts(ulnode, singlePartVec); // 3
       bulkData->change_entity_parts(urnode, singlePartVec); // 2
       bulkData->change_entity_parts(ulnodeb, singlePartVec); // 7
       bulkData->change_entity_parts(urnodeb, singlePartVec); // 6
    }
    if (xyz[eles[i][0]-1][2] == 0.0) {
       singlePartVec[0] = nsPartVec["NodeSet4"];
       bulkData->change_entity_parts(llnode, singlePartVec); // 0
       bulkData->change_entity_parts(lrnode, singlePartVec); // 1
       bulkData->change_entity_parts(ulnode, singlePartVec); // 3
       bulkData->change_entity_parts(urnode, singlePartVec); // 2
    }
    if (xyz[eles[i][4]-1][2] == 1.0) {
       singlePartVec[0] = nsPartVec["NodeSet5"];
       bulkData->change_entity_parts(llnodeb, singlePartVec); // 4
       bulkData->change_entity_parts(lrnodeb, singlePartVec); // 5
       bulkData->change_entity_parts(ulnodeb, singlePartVec); // 7
       bulkData->change_entity_parts(urnodeb, singlePartVec); // 6
    }

     // If first node has z=0, identify it as a Bottom NS
     if ( xyz[eles[i][0]-1][2] == 0.0) {
       singlePartVec[0] = nsPartVec["Bottom"];
       bulkData->change_entity_parts(llnode, singlePartVec); // 0
       bulkData->change_entity_parts(lrnode, singlePartVec); // 1
       bulkData->change_entity_parts(ulnode, singlePartVec); // 3
       bulkData->change_entity_parts(urnode, singlePartVec); // 2
     }
  }
  if (have_bf == true) {
    *out << "Setting basal surface connectivity from bf file provided..." << std::endl;  
    for (int i=0; i<basal_face_map->NumMyElements(); i++) {
       singlePartVec[0] = ssPartVec["Basal"];
       sideID = basal_face_map->GID(i); 
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity& side  = bulkData->declare_entity(metaData->side_rank(), 1 + side_id, singlePartVec);

       const unsigned int elem_GID = bf[i][0];
       //std::cout << "elem_GID: " << elem_GID << std::endl; 
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity& elem  = bulkData->declare_entity(metaData->element_rank(), elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  4 /*local side id*/);
       stk::mesh::Entity& llnode = bulkData->declare_entity(metaData->node_rank(), bf[i][1], nodePartVec);
       stk::mesh::Entity& lrnode = bulkData->declare_entity(metaData->node_rank(), bf[i][2], nodePartVec);
       stk::mesh::Entity& urnode = bulkData->declare_entity(metaData->node_rank(), bf[i][3], nodePartVec);
       stk::mesh::Entity& ulnode = bulkData->declare_entity(metaData->node_rank(), bf[i][4], nodePartVec);
       
       bulkData->declare_relation(side, llnode, 0);
       bulkData->declare_relation(side, ulnode, 3);
       bulkData->declare_relation(side, urnode, 2);
       bulkData->declare_relation(side, lrnode, 1);
    }
  }

  bulkData->modification_end();
}
void
Aeras::SpectralOutputSTKMeshStruct::setFieldAndBulkData(
                                               const Teuchos::RCP<const Teuchos_Comm>& commT,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const Albany::AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const unsigned int worksetSize)

{
#ifdef OUTPUT_TO_SCREEN
  *out << "DEBUG: " << __PRETTY_FUNCTION__ << "\n";
#endif
  this->SetupFieldData(commT, neq_, req, sis, worksetSize);

  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);

  //FIXME?: assuming for now 1 element block
  unsigned int ebNo = 0;

  typedef Albany::AbstractSTKFieldContainer::ScalarFieldType ScalarFieldType;
  typedef Albany::AbstractSTKFieldContainer::QPScalarFieldType ElemScalarFieldType;

  Albany::AbstractSTKFieldContainer::VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();

  if (ElemType == QUAD) { //Quads
#ifdef OUTPUT_TO_SCREEN
    std::cout << "Spectral Mesh # ws, # eles: " << wsElNodeID.size() << ", " << wsElNodeID[0].size() << std::endl;
    for (int ws = 0; ws < wsElNodeID.size(); ws++){
      for (int e = 0; e < wsElNodeID[ws].size(); e++){
        std::cout << "Spectral Mesh Element " << e << ": Nodes = ";
        for (size_t inode = 0; inode < points_per_edge*points_per_edge; ++inode)
          std::cout << wsElNodeID[ws][e][inode] << " ";
              std::cout << std::endl;
      }
    }
#endif

    GO count = 0;
    GO numOutputEles = wsElNodeID[0].size()*(points_per_edge-1)*(points_per_edge-1);
    for (int ws = 0; ws < wsElNodeID.size(); ws++){             // workset
      for (int e = 0; e < wsElNodeID[ws].size(); e++){          // cell
        for (int i=0; i<points_per_edge-1; i++) {           //Each spectral element broken into (points_per_edge-1)^2 bilinear elements
          for (int j=0; j<points_per_edge-1; j++) {
            //Set connectivity for new mesh
            const GO elem_GID = count + numOutputEles*commT->getRank();
            count++;
            stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
            singlePartVec[0] = partVec[ebNo];
            //Add 1 to elem_id in the following line b/c STK is 1-based whereas wsElNodeID is 0-based
            stk::mesh::Entity elem = bulkData->declare_entity(stk::topology::ELEMENT_RANK, 1+elem_id, singlePartVec);
            stk::mesh::Entity node0 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                      1+wsElNodeID[ws][e][i+j*points_per_edge], nodePartVec);
            stk::mesh::Entity node1 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                      1+wsElNodeID[ws][e][i+1+j*points_per_edge], nodePartVec);
            stk::mesh::Entity node2 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                      1+wsElNodeID[ws][e][i+points_per_edge+1+j*points_per_edge], nodePartVec);
            stk::mesh::Entity node3 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                      1+wsElNodeID[ws][e][i+points_per_edge+j*points_per_edge], nodePartVec);
#ifdef OUTPUT_TO_SCREEN
            std::cout << "ws, e, i , j " << ws << ", " << e << ", " << i << ", " << j << std::endl;
            std::cout << "Output Mesh elem_GID, node0, node1, node2, node3: " << elem_GID << ", "
                      << wsElNodeID[ws][e][i+j*points_per_edge] << ", "
                      << wsElNodeID[ws][e][i+1+j*points_per_edge] << ", "
                      << wsElNodeID[ws][e][i+points_per_edge+1+j*points_per_edge] << ", "
                      << wsElNodeID[ws][e][i+points_per_edge+j*points_per_edge]
                      << std::endl;
#endif
            bulkData->declare_relation(elem, node0, 0);
            bulkData->declare_relation(elem, node1, 1);
            bulkData->declare_relation(elem, node2, 2);
            bulkData->declare_relation(elem, node3, 3);

            //Set coordinates of new mesh
            double* coord;
            //set node 0 in STK bilinear mesh
            coord = stk::mesh::field_data(*coordinates_field, node0);
#ifdef OUTPUT_TO_SCREEN
           std::cout << "Output mesh node0 coords: " << coords[ws][e][i+j*points_per_edge][0]
                     << ", " << coords[ws][e][i+j*points_per_edge][1] << ", " << coords[ws][e][i+j*points_per_edge][2] << std::endl;
#endif
            coord[0] = coords[ws][e][i+j*points_per_edge][0];
            coord[1] = coords[ws][e][i+j*points_per_edge][1];
            coord[2] = coords[ws][e][i+j*points_per_edge][2];
            //set node 1 in STK bilinear mesh
            coord = stk::mesh::field_data(*coordinates_field, node1);
#ifdef OUTPUT_TO_SCREEN
            std::cout << "Output mesh node1 coords: " << coords[ws][e][i+1+j*points_per_edge][0]
                      << ", " << coords[ws][e][i+1+j*points_per_edge][1] << ", " << coords[ws][e][i+1+j*points_per_edge][2] << std::endl;
#endif
            coord[0] = coords[ws][e][i+1+j*points_per_edge][0];
            coord[1] = coords[ws][e][i+1+j*points_per_edge][1];
            coord[2] = coords[ws][e][i+1+j*points_per_edge][2];
            //set node 2 in STK bilinear mesh
            coord = stk::mesh::field_data(*coordinates_field, node2);
#ifdef OUTPUT_TO_SCREEN
            std::cout << "Output mesh node2 coords: " << coords[ws][e][i+points_per_edge+1+j*points_per_edge][0]
                      << ", " << coords[ws][e][i+points_per_edge+1+j*points_per_edge][1]
                      << ", " << coords[ws][e][i+points_per_edge+1+j*points_per_edge][2] << std::endl;
#endif
            coord[0] = coords[ws][e][i+points_per_edge+1+j*points_per_edge][0];
            coord[1] = coords[ws][e][i+points_per_edge+1+j*points_per_edge][1];
            coord[2] = coords[ws][e][i+points_per_edge+1+j*points_per_edge][2];
            //set node 3 in STK bilinear mesh
            coord = stk::mesh::field_data(*coordinates_field, node3);
#ifdef OUTPUT_TO_SCREEN
            std::cout << "Output mesh node3 coords: " << coords[ws][e][i+points_per_edge+j*points_per_edge][0]
                      << ", " << coords[ws][e][i+points_per_edge+j*points_per_edge][1]
                      << ", " << coords[ws][e][i+points_per_edge+j*points_per_edge][2] << std::endl;
#endif
            coord[0] = coords[ws][e][i+points_per_edge+j*points_per_edge][0];
            coord[1] = coords[ws][e][i+points_per_edge+j*points_per_edge][1];
            coord[2] = coords[ws][e][i+points_per_edge+j*points_per_edge][2];
          }
        }
      }
    }
  }
  else if (ElemType == LINE) { //Lines (for xz hydrostatic)
    //IKT, 8/28/15: the following code needs testing
#ifdef OUTPUT_TO_SCREEN
    std::cout << "Spectral Mesh # ws, # eles: " << wsElNodeID.size() << ", " << wsElNodeID[0].size() << std::endl;
    for (int ws = 0; ws < wsElNodeID.size(); ws++){
      for (int e = 0; e < wsElNodeID[ws].size(); e++){
        std::cout << "Spectral Mesh Element " << e << ": Nodes = ";
        for (size_t inode = 0; inode < points_per_edge; ++inode)
          std::cout << wsElNodeID[ws][e][inode] << " ";
              std::cout << std::endl;
      }
    }
#endif
    GO count = 0;
    GO numOutputEles = wsElNodeID[0].size()*(points_per_edge-1);
    for (int ws = 0; ws < wsElNodeID.size(); ws++){             // workset
      for (int e = 0; e < wsElNodeID[ws].size(); e++){          // cell
        for (int i=0; i<points_per_edge-1; i++) {           //Each spectral element broken into (points_per_edge-1) linear elements
          //Set connectivity for new mesh
          const GO elem_GID = count + numOutputEles*commT->getRank()*commT->getSize();
          count++;
          stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
          singlePartVec[0] = partVec[ebNo];
          //Add 1 to elem_id in the following line b/c STK is 1-based whereas wsElNodeID is 0-based
          stk::mesh::Entity elem = bulkData->declare_entity(stk::topology::ELEMENT_RANK, 1+elem_id, singlePartVec);
          stk::mesh::Entity node0 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                    1+wsElNodeID[ws][e][i], nodePartVec);
          stk::mesh::Entity node1 = bulkData->declare_entity(stk::topology::NODE_RANK,
                                    1+wsElNodeID[ws][e][i+1], nodePartVec);
#ifdef OUTPUT_TO_SCREEN
          std::cout << "ws, e, i " << ws << ", " << e << ", " << i  << std::endl;
          std::cout << "Output Mesh elem_GID, node0, node1: " << elem_GID << ", "
                    << wsElNodeID[ws][e][i] << ", "
                    << wsElNodeID[ws][e][i+1] << std::endl;
#endif
          bulkData->declare_relation(elem, node0, 0);
          bulkData->declare_relation(elem, node1, 1);

          //Set coordinates of new mesh
          double* coord;
          //set node 0 in STK linear mesh
          coord = stk::mesh::field_data(*coordinates_field, node0);
          coord[0] = coords[ws][e][i][0];
#ifdef OUTPUT_TO_SCREEN
          std::cout << "Output mesh node0 x-coord: " << coord[0] << std::endl;  
#endif 
          //set node 1 in STK linear mesh 
          coord = stk::mesh::field_data(*coordinates_field, node1);
          coord[0] = coords[ws][e][i+1][0];
          if ((periodic == true) && (coords[ws][e][i+1][0] == scale))
            coord[0] = 0.0; 
#ifdef OUTPUT_TO_SCREEN
          std::cout << "Output mesh node1 x-coord: " << coord[0] << std::endl;  
#endif 
        }
      }
    }
  }

  Albany::fix_node_sharing(*bulkData);
  bulkData->modification_end();
}
void
Albany::CismSTKMeshStruct::constructMesh(
                                               const Teuchos::RCP<const Teuchos_Comm>& commT,
                                               const Teuchos::RCP<Teuchos::ParameterList>& params,
                                               const unsigned int neq_,
                                               const AbstractFieldContainer::FieldContainerRequirements& req,
                                               const Teuchos::RCP<Albany::StateInfoStruct>& sis,
                                               const unsigned int worksetSize)
{
  this->SetupFieldData(commT, neq_, req, sis, worksetSize);

  metaData->commit();

  bulkData->modification_begin(); // Begin modifying the mesh

  stk::mesh::PartVector nodePartVec;
  stk::mesh::PartVector singlePartVec(1);
  stk::mesh::PartVector emptyPartVec;
  if (debug_output_verbosity == 2) {
    std::cout << "elem_mapT # elements: " << elem_mapT->getNodeNumElements() << std::endl;
    std::cout << "node_mapT # elements: " << node_mapT->getNodeNumElements() << std::endl;
  }
  unsigned int ebNo = 0; //element block #???
  int sideID = 0;

  typedef AbstractSTKFieldContainer::ScalarFieldType ScalarFieldType;
  typedef AbstractSTKFieldContainer::VectorFieldType VectorFieldType;
  typedef AbstractSTKFieldContainer::QPScalarFieldType ElemScalarFieldType;

  VectorFieldType* coordinates_field = fieldContainer->getCoordinatesField();
  ScalarFieldType* surfaceHeight_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "surface_height");
  ScalarFieldType* thickness_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "thickness");
  ScalarFieldType* dsurfaceHeight_dx_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "xgrad_surface_height");
  ScalarFieldType* dsurfaceHeight_dy_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "ygrad_surface_height");
  ElemScalarFieldType* flowFactor_field = metaData->get_field<ElemScalarFieldType>(stk::topology::ELEMENT_RANK, "flow_factor");
  ElemScalarFieldType* temperature_field = metaData->get_field<ElemScalarFieldType>(stk::topology::ELEMENT_RANK, "temperature");
  ScalarFieldType* basal_friction_field = metaData->get_field<ScalarFieldType>(stk::topology::NODE_RANK, "basal_friction");
  VectorFieldType* dirichlet_field = metaData->get_field<VectorFieldType>(stk::topology::NODE_RANK, "dirichlet_field");

  if(!surfaceHeight_field)
     have_sh = false;
  if(!thickness_field)
     have_thck = false;
  if(!dsurfaceHeight_dx_field || !dsurfaceHeight_dy_field)
     have_shGrad = false;
  if(!flowFactor_field)
     have_flwa = false;
  if(!temperature_field)
     have_temp = false;
  if(!basal_friction_field)
     have_beta = false;

  double* coord;
  int node_GID;
  unsigned int node_LID;

  for (int i=0; i<elem_mapT->getNodeNumElements(); i++) {
     const unsigned int elem_GID = elem_mapT->getGlobalElement(i);
     stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
     singlePartVec[0] = partVec[ebNo];
     //I am assuming the ASCII mesh is 1-based not 0-based, so no need to add 1 for STK mesh 
     stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, 1+elem_id, singlePartVec);
     for (int j=0; j<8; j++) { //loop over 8 nodes of each element
     //Set element connectivity and coordinates
       stk::mesh::Entity node = bulkData->declare_entity(stk::topology::NODE_RANK, eles[i][j], nodePartVec);
       bulkData->declare_relation(elem, node, j);
       
       node_GID = eles[i][j]-1;
       node_LID = node_mapT->getLocalElement(node_GID);
       coord = stk::mesh::field_data(*coordinates_field, node);
       coord[0] = xyz[node_LID][0];   coord[1] = xyz[node_LID][1];   coord[2] = xyz[node_LID][2];
       //set surface height
       if (have_sh) {
         double* sHeight;
         sHeight = stk::mesh::field_data(*surfaceHeight_field, node);
         sHeight[0] = sh[node_LID];
       }
       //set thickness field
       if (have_thck) {
         double* thickness;
         thickness = stk::mesh::field_data(*thickness_field, node);
         thickness[0] = thck[node_LID];
       }
       //set gradients of surface height
       if (have_shGrad) {
         double* dsHeight_dx; 
         double* dsHeight_dy;
         dsHeight_dx = stk::mesh::field_data(*dsurfaceHeight_dx_field, node);
         dsHeight_dy = stk::mesh::field_data(*dsurfaceHeight_dy_field, node);
         dsHeight_dx[0] = shGrad[node_LID][0];
         dsHeight_dy[0] = shGrad[node_LID][1];
       }
       //set Dirichlet BCs to those passed from CISM.
       if (have_dirichlet) {
         double* dirichlet = stk::mesh::field_data(*dirichlet_field,node);
         dirichlet[0] = uvel[node_LID];
         dirichlet[1] = vvel[node_LID];
       }
       //set basal friction
       if (have_beta) { 
         double* bFriction; 
         bFriction = stk::mesh::field_data(*basal_friction_field, node);
         bFriction[0] = beta[node_LID];
      }
     }
     
     //Set Dirichlet nodesets 
     singlePartVec[0] = nsPartVec["NodeSetDirichlet"];
     for (int j=0; j<8; j++) { //loop over 8 nodes of each element
       node_GID = eles[i][j]-1;
       node_LID = node_mapT->getLocalElement(node_GID);
       if (dirichletNodeMask[node_LID] == 1) {
         stk::mesh::Entity node = bulkData->declare_entity(stk::topology::NODE_RANK, eles[i][j], nodePartVec);
         bulkData->change_entity_parts(node, singlePartVec); 
       }
     }

     //set fields that live at the elements
     if (have_flwa) {
       double *flowFactor = stk::mesh::field_data(*flowFactor_field, elem); 
       //i is elem_LID (element local ID);
       //*out << "i: " << i <<", flwa: " << flwa[i] << std::endl;
       flowFactor[0] = flwa[i];
     }
     if (have_temp) {
       double *temperature = stk::mesh::field_data(*temperature_field, elem); 
       //i is elem_LID (element local ID);
       //*out << "i: " << i <<", temp: " << temperature[i] << std::endl;
       temperature[0] = temper[i];
     }
     
     //set basal face connectivity
  }

  if (have_bf == true) {
    if (debug_output_verbosity != 0) *out << "Setting basal surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Basal"];
    for (int i=0; i<basal_face_mapT->getNodeNumElements(); i++) {
       sideID = basal_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = bf[i][0];
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  4 /*local side id*/);

       stk::mesh::Entity llnode = bulkData->declare_entity(stk::topology::NODE_RANK, bf[i][1], nodePartVec);
       stk::mesh::Entity lrnode = bulkData->declare_entity(stk::topology::NODE_RANK, bf[i][2], nodePartVec);
       stk::mesh::Entity urnode = bulkData->declare_entity(stk::topology::NODE_RANK, bf[i][3], nodePartVec);
       stk::mesh::Entity ulnode = bulkData->declare_entity(stk::topology::NODE_RANK, bf[i][4], nodePartVec);
       
       bulkData->declare_relation(side, llnode, 0);
       bulkData->declare_relation(side, ulnode, 3);
       bulkData->declare_relation(side, urnode, 2);
       bulkData->declare_relation(side, lrnode, 1);
    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }
  if (have_tf == true) {
    if (debug_output_verbosity != 0) *out << "Setting top surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Top"];
    for (int i=0; i<top_face_mapT->getNodeNumElements(); i++) {
       sideID = top_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = tf[i][0];
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  5 /*local side id*/);

       //TODO: check numbering convention! 
       stk::mesh::Entity llnode = bulkData->declare_entity(stk::topology::NODE_RANK, tf[i][1], nodePartVec);
       stk::mesh::Entity lrnode = bulkData->declare_entity(stk::topology::NODE_RANK, tf[i][2], nodePartVec);
       stk::mesh::Entity urnode = bulkData->declare_entity(stk::topology::NODE_RANK, tf[i][3], nodePartVec);
       stk::mesh::Entity ulnode = bulkData->declare_entity(stk::topology::NODE_RANK, tf[i][4], nodePartVec);
       
       bulkData->declare_relation(side, llnode, 0);
       bulkData->declare_relation(side, ulnode, 3);
       bulkData->declare_relation(side, urnode, 2);
       bulkData->declare_relation(side, lrnode, 1);
    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }

  //set lateral face connectivity
  if (have_wf == true) {
    if (debug_output_verbosity != 0) *out << "Setting west lateral surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Lateral"];
    for (int i=0; i<west_face_mapT->getNodeNumElements(); i++) {
       sideID = west_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = wf[i][0];
       if (debug_output_verbosity != 0) *out << "   element " << elem_GID << " has a west lateral face." << std::endl; 
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  3 /*local side id*/);

       stk::mesh::Entity llnode = bulkData->declare_entity(stk::topology::NODE_RANK, wf[i][1], nodePartVec); //OK
       stk::mesh::Entity ulnode = bulkData->declare_entity(stk::topology::NODE_RANK, wf[i][2], nodePartVec); //OK
       stk::mesh::Entity ulnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, wf[i][3], nodePartVec); //OK
       stk::mesh::Entity llnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, wf[i][4], nodePartVec); //OK
       
       bulkData->declare_relation(side, llnode, 0);
       bulkData->declare_relation(side, llnodeb, 2);
       bulkData->declare_relation(side, ulnodeb, 3);
       bulkData->declare_relation(side, ulnode, 1);

    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }
  if (have_ef == true) {
    if (debug_output_verbosity != 0) *out << "Setting east lateral surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Lateral"];
    for (int i=0; i<east_face_mapT->getNodeNumElements(); i++) {
       sideID = east_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = ef[i][0];
       if (debug_output_verbosity != 0) *out << "   element " << elem_GID << " has an east lateral face." << std::endl; 
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  1 /*local side id*/);

       stk::mesh::Entity lrnode = bulkData->declare_entity(stk::topology::NODE_RANK, ef[i][1], nodePartVec);
       stk::mesh::Entity lrnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, ef[i][2], nodePartVec);
       stk::mesh::Entity urnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, ef[i][3], nodePartVec);
       stk::mesh::Entity urnode = bulkData->declare_entity(stk::topology::NODE_RANK, ef[i][4], nodePartVec);
       
       bulkData->declare_relation(side, lrnode, 0);
       bulkData->declare_relation(side, urnode, 1);
       bulkData->declare_relation(side, urnodeb, 3);
       bulkData->declare_relation(side, lrnodeb, 2);
    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }
  if (have_sf == true) {
    if (debug_output_verbosity != 0) *out << "Setting south lateral surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Lateral"];
    for (int i=0; i<south_face_mapT->getNodeNumElements(); i++) {
       sideID = south_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = sf[i][0];
       if (debug_output_verbosity != 0) *out << "   element " << elem_GID << " has a south lateral face." << std::endl; 
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  0 /*local side id*/);

       stk::mesh::Entity llnode = bulkData->declare_entity(stk::topology::NODE_RANK, sf[i][1], nodePartVec);
       stk::mesh::Entity lrnode = bulkData->declare_entity(stk::topology::NODE_RANK, sf[i][2], nodePartVec);
       stk::mesh::Entity lrnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, sf[i][3], nodePartVec);
       stk::mesh::Entity llnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, sf[i][4], nodePartVec);
       
       bulkData->declare_relation(side, llnode, 0);
       bulkData->declare_relation(side, lrnode, 1);
       bulkData->declare_relation(side, lrnodeb, 3);
       bulkData->declare_relation(side, llnodeb, 2);
    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }
  if (have_nf == true) {
    if (debug_output_verbosity != 0) *out << "Setting north lateral surface connectivity from data provided..." << std::endl;
    singlePartVec[0] = ssPartVec["Lateral"];
    for (int i=0; i<north_face_mapT->getNodeNumElements(); i++) {
       sideID = north_face_mapT->getGlobalElement(i);
       stk::mesh::EntityId side_id = (stk::mesh::EntityId)(sideID);
       stk::mesh::Entity side  = bulkData->declare_entity(metaData->side_rank(),side_id+1, singlePartVec);
       const unsigned int elem_GID = nf[i][0];
       if (debug_output_verbosity !=0) *out << "   element " << elem_GID << " has a north lateral face." << std::endl; 
       stk::mesh::EntityId elem_id = (stk::mesh::EntityId) elem_GID;
       stk::mesh::Entity elem  = bulkData->declare_entity(stk::topology::ELEMENT_RANK, elem_id, emptyPartVec);
       bulkData->declare_relation(elem, side,  2 /*local side id*/);

       stk::mesh::Entity ulnode = bulkData->declare_entity(stk::topology::NODE_RANK, nf[i][1], nodePartVec);
       stk::mesh::Entity ulnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, nf[i][2], nodePartVec);
       stk::mesh::Entity urnodeb = bulkData->declare_entity(stk::topology::NODE_RANK, nf[i][3], nodePartVec);
       stk::mesh::Entity urnode = bulkData->declare_entity(stk::topology::NODE_RANK, nf[i][4], nodePartVec);
       
       bulkData->declare_relation(side, urnode, 0);
       bulkData->declare_relation(side, ulnode, 1);
       bulkData->declare_relation(side, ulnodeb, 3);
       bulkData->declare_relation(side, urnodeb, 2);
    }
    if (debug_output_verbosity != 0) *out << "...done." << std::endl;
  }

  Albany::fix_node_sharing(*bulkData);
  bulkData->modification_end();
}