Beispiel #1
0
void Grid::InitializeConnectivity(
	bool fAllocate
) {

	// Clear all existing neighbors fro all active patches
	for (int n = 0; n < m_vecActiveGridPatches.size(); n++) {
		m_vecActiveGridPatches[n]->m_connect.ClearNeighbors();
	}

	// Loop through all exchange buffers
	const ExchangeBufferRegistry::ExchangeBufferInfoVector & vecRegistry =
		m_aExchangeBufferRegistry.GetRegistry();

	for (int m = 0; m < vecRegistry.size(); m++) {

		const ExchangeBufferInfo & info = vecRegistry[m];

		// If the GridPatch associated with this exchange buffer is active,
		// add neighbors
		GridPatch * pPatch = NULL;
		for (int n = 0; n < m_vecActiveGridPatches.size(); n++) {
			if (m_vecActiveGridPatchIndices[n] == info.ixSourcePatch) {
				pPatch = m_vecActiveGridPatches[n];
				break;
			}
		}

		if (pPatch != NULL) {

			const PatchBox & boxSource = GetPatchBox(info.ixSourcePatch);
			const PatchBox & boxTarget = GetPatchBox(info.ixTargetPatch);

			// Build the new ExteriorNeighbor
			ExteriorNeighbor * pNeighbor =
				new ExteriorNeighbor(info);

			if (fAllocate) {
				m_aExchangeBufferRegistry.Allocate(m);
			}

			pNeighbor->AttachBuffers(
				m_aExchangeBufferRegistry.GetRecvBufferPtr(m),
				m_aExchangeBufferRegistry.GetSendBufferPtr(m));

			pPatch->m_connect.AddExteriorNeighbor(pNeighbor);
		}
	}
}
Beispiel #2
0
int Grid::GetTotalNodeCount(
	DataLocation loc
) const {

	// Total number of nodes over all patches of grid
	int nTotalNodes = 0;

	// Loop over all patches and obtain total node count
	for (int n = 0; n < m_aPatchBoxes.GetRows(); n++) {
		const PatchBox & box = GetPatchBox(n);

		int nPatchNodes;
		if (loc == DataLocation_Node) {
			nPatchNodes = box.GetTotalNodes() * GetRElements();
		} else if (loc == DataLocation_REdge) {
			nPatchNodes = box.GetTotalNodes() * (GetRElements() + 1);
		} else {
			_EXCEPTIONT("Invalid location");
		}

		nTotalNodes += nPatchNodes;
	}

	return nTotalNodes;
}
Beispiel #3
0
void Grid::RegisterExchangeBuffer(
	int ixSourcePatch,
	int ixTargetPatch,
	Direction dir
) {
	const PatchBox & box = GetPatchBox(ixSourcePatch);

	// First patch coordinate index
	int ixFirst;
	int ixSecond;

	if ((dir == Direction_Right) ||
		(dir == Direction_Left)
	) {
		ixFirst  = box.GetBInteriorBegin();
		ixSecond = box.GetBInteriorEnd();

	} else if (
		(dir == Direction_Top) ||
		(dir == Direction_Bottom)
	) {
		ixFirst  = box.GetAInteriorBegin();
		ixSecond = box.GetAInteriorEnd();

	} else if (dir == Direction_TopRight) {
		ixFirst  = box.GetAInteriorEnd()-1;
		ixSecond = box.GetBInteriorEnd()-1;

	} else if (dir == Direction_TopLeft) {
		ixFirst  = box.GetAInteriorBegin();
		ixSecond = box.GetBInteriorEnd()-1;

	} else if (dir == Direction_BottomLeft) {
		ixFirst  = box.GetAInteriorBegin();
		ixSecond = box.GetBInteriorBegin();

	} else if (dir == Direction_BottomRight) {
		ixFirst  = box.GetAInteriorEnd()-1;
		ixSecond = box.GetBInteriorBegin();

	} else {
		_EXCEPTIONT("Invalid direction");
	}

	// Exterior connect
	RegisterExchangeBuffer(
		ixSourcePatch,
		ixTargetPatch,
		dir,
		ixFirst,
		ixSecond);
}
Beispiel #4
0
GridPatch * GridCartesianGLL::NewPatch(
	int ixPatch
) {
	const PatchBox & box = GetPatchBox(ixPatch);

	return (
		new GridPatchCartesianGLL(
			(*this),
			ixPatch,
			box,
			m_nHorizontalOrder,
			m_nVerticalOrder));
}
Beispiel #5
0
void Grid::InitializeExchangeBuffersFromPatch(
	int ixSourcePatch
) {
	const PatchBox & box = GetPatchBox(ixSourcePatch);

	// Vector of nodal points around element
	int nPerimeter = box.GetInteriorPerimeter() + 4;

	DataArray1D<int> vecIxA(nPerimeter);
	DataArray1D<int> vecIxB(nPerimeter);
	DataArray1D<int> vecPanel(nPerimeter);
	DataArray1D<int> vecPatch(nPerimeter);

	// Perimeter node index
	int ix = 0;

	// Bottom-left corner
	vecIxA[ix] = box.GetAGlobalInteriorBegin()-1;
	vecIxB[ix] = box.GetBGlobalInteriorBegin()-1;
	vecPanel[ix] = box.GetPanel();
	ix++;

	// Bottom edge
	for (int i = box.GetAGlobalInteriorBegin();
	         i < box.GetAGlobalInteriorEnd(); i++
	) {
		vecIxA[ix] = i;
		vecIxB[ix] = box.GetBGlobalInteriorBegin()-1;
		vecPanel[ix] = box.GetPanel();
		ix++;
	}

	// Bottom-right corner
	vecIxA[ix] = box.GetAGlobalInteriorEnd();
	vecIxB[ix] = box.GetBGlobalInteriorBegin()-1;
	vecPanel[ix] = box.GetPanel();
	ix++;

	// Right edge
	for (int j = box.GetBGlobalInteriorBegin();
	         j < box.GetBGlobalInteriorEnd(); j++
	) {
		vecIxA[ix] = box.GetAGlobalInteriorEnd();
		vecIxB[ix] = j;
		vecPanel[ix] = box.GetPanel();
		ix++;
	}

	// Top-right corner
	vecIxA[ix] = box.GetAGlobalInteriorEnd();
	vecIxB[ix] = box.GetBGlobalInteriorEnd();
	vecPanel[ix] = box.GetPanel();
	ix++;

	// Top edge
	for (int i = box.GetAGlobalInteriorEnd()-1;
	         i >= box.GetAGlobalInteriorBegin(); i--
	) {
		vecIxA[ix] = i;
		vecIxB[ix] = box.GetBGlobalInteriorEnd();
		vecPanel[ix] = box.GetPanel();
		ix++;
	}

	// Top-left corner
	vecIxA[ix] = box.GetAGlobalInteriorBegin()-1;
	vecIxB[ix] = box.GetBGlobalInteriorEnd();
	vecPanel[ix] = box.GetPanel();
	ix++;

	// Left edge
	for (int j = box.GetBGlobalInteriorEnd()-1;
	         j >= box.GetBGlobalInteriorBegin(); j--
	) {
		vecIxA[ix] = box.GetAGlobalInteriorBegin()-1;
		vecIxB[ix] = j;
		vecPanel[ix] = box.GetPanel();
		ix++;
	}

	// Get neighboring patches at each halo node
	GetPatchFromCoordinateIndex(
		box.GetRefinementLevel(),
		vecIxA,
		vecIxB,
		vecPanel,
		vecPatch,
		ix);

	// Verify index length
	if (ix != box.GetInteriorPerimeter() + 4) {
		_EXCEPTIONT("Index mismatch");
	}

	// Reset index
	ix = 0;

	// Add connectivity to bottom-left corner
	if (vecPatch[ix] != GridPatch::InvalidIndex) {
		RegisterExchangeBuffer(
			ixSourcePatch,
			vecPatch[ix],
			Direction_BottomLeft);
	}

	ix++;

	// Add connectivity to bottom edge: Look for segments along each
	// edge that connect to distinct patches and construct corresponding
	// ExteriorNeighbors.
	{
		int ixFirstBegin = box.GetAInteriorBegin();
		int iCurrentPatch = vecPatch[ix];

		for (int i = ixFirstBegin; i <= box.GetAInteriorEnd(); i++) {
			if ((i == box.GetAInteriorEnd()) ||
				(vecPatch[ix] != iCurrentPatch)
			) {
				RegisterExchangeBuffer(
					ixSourcePatch,
					iCurrentPatch,
					Direction_Bottom,
					ixFirstBegin,
					i);

				if (i != box.GetAInteriorEnd()) {
					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_BottomLeft,
						i,
						box.GetBInteriorBegin());

					ixFirstBegin = i;
					iCurrentPatch = vecPatch[ix];

					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_BottomRight,
						i - 1,
						box.GetBInteriorBegin());
				}
			}
			if (i != box.GetAInteriorEnd()) {
				ix++;
			}
		}
	}

	// Add connectivity to bottom-right corner
	if (vecPatch[ix] != GridPatch::InvalidIndex) {
		RegisterExchangeBuffer(
			ixSourcePatch,
			vecPatch[ix],
			Direction_BottomRight);
	}

	ix++;

	// Add connectivity to right edge
	{
		int ixFirstBegin = box.GetBInteriorBegin();
		int iCurrentPatch = vecPatch[ix];

		for (int j = ixFirstBegin; j <= box.GetBInteriorEnd(); j++) {
			if ((j == box.GetBInteriorEnd()) ||
				(vecPatch[ix] != iCurrentPatch)
			) {
				RegisterExchangeBuffer(
					ixSourcePatch,
					iCurrentPatch,
					Direction_Right,
					ixFirstBegin,
					j);

				if (j != box.GetBInteriorEnd()) {
					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_BottomRight,
						box.GetAInteriorEnd()-1,
						j);

					ixFirstBegin = j;
					iCurrentPatch = vecPatch[ix];

					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_TopRight,
						box.GetAInteriorEnd()-1,
						j - 1);
				}
			}
			if (j != box.GetBInteriorEnd()) {
				ix++;
			}
		}
	}

	// Add connectivity to top-right corner
	if (vecPatch[ix] != GridPatch::InvalidIndex) {
		RegisterExchangeBuffer(
			ixSourcePatch,
			vecPatch[ix],
			Direction_TopRight);
	}

	ix++;

	// Add connectivity to top edge
	{
		int ixFirstEnd = box.GetAInteriorEnd();
		int iCurrentPatch = vecPatch[ix];

		for (int i = ixFirstEnd-1; i >= box.GetAInteriorBegin()-1; i--) {
			if ((i == box.GetAInteriorBegin()-1) ||
				(vecPatch[ix] != iCurrentPatch)
			) {
				RegisterExchangeBuffer(
					ixSourcePatch,
					iCurrentPatch,
					Direction_Top,
					i + 1,
					ixFirstEnd);

				if (i != box.GetAInteriorBegin()-1) {
					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_TopRight,
						i,
						box.GetBInteriorEnd()-1);

					ixFirstEnd = i + 1;
					iCurrentPatch = vecPatch[ix];

					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_TopLeft,
						i + 1,
						box.GetBInteriorEnd()-1);
				}
			}
			if (i != box.GetAInteriorBegin()-1) {
				ix++;
			}
		}
	}

	// Add connectivity to top-left corner
	if (vecPatch[ix] != GridPatch::InvalidIndex) {
		RegisterExchangeBuffer(
			ixSourcePatch,
			vecPatch[ix],
			Direction_TopLeft);
	}

	ix++;

	// Add connectivity to top edge
	{
		int ixFirstEnd = box.GetBInteriorEnd();
		int iCurrentPatch = vecPatch[ix];

		for (int j = ixFirstEnd-1; j >= box.GetBInteriorBegin()-1; j--) {
			if ((j == box.GetBInteriorBegin()-1) ||
				(vecPatch[ix] != iCurrentPatch)
			) {
				RegisterExchangeBuffer(
					ixSourcePatch,
					iCurrentPatch,
					Direction_Left,
					j + 1,
					ixFirstEnd);

				if (j != box.GetBInteriorBegin()-1) {
					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_TopLeft,
						box.GetAInteriorBegin(),
						j);

					ixFirstEnd = j + 1;
					iCurrentPatch = vecPatch[ix];

					RegisterExchangeBuffer(
						ixSourcePatch,
						iCurrentPatch,
						Direction_BottomLeft,
						box.GetAInteriorBegin(),
						j + 1);
				}
			}
			if (j != box.GetBInteriorBegin()-1) {
				ix++;
			}
		}
	}

	// Verify index length
	if (ix != box.GetInteriorPerimeter() + 4) {
		_EXCEPTIONT("Index mismatch");
	}
}
Beispiel #6
0
void Grid::RegisterExchangeBuffer(
	int ixSourcePatch,
	int ixTargetPatch,
	Direction dir,
	int ixFirst,
	int ixSecond
) {
	if (ixSourcePatch == GridPatch::InvalidIndex) {
		_EXCEPTIONT("Invalid ixSourcePatch");
	}

	// Check for NULL patches (do nothing)
	if (ixTargetPatch == GridPatch::InvalidIndex) {
		return;
	}

	// Get the GridPatch's PatchBox
	const PatchBox & boxSource = GetPatchBox(ixSourcePatch);
	const PatchBox & boxTarget = GetPatchBox(ixTargetPatch);

	// Build key
	ExchangeBufferInfo info;
	info.ixSourcePatch = ixSourcePatch;
	info.ixTargetPatch = ixTargetPatch;
	info.dir = dir;

	// Build exhange buffer metadata
	info.ixFirst = ixFirst;
	info.ixSecond = ixSecond;

	// Get number of components
	const Model & model = GetModel();

	const EquationSet & eqn = model.GetEquationSet();

	size_t sStateTracerMaxVariables;
	if (eqn.GetComponents() > eqn.GetTracers()) {
		sStateTracerMaxVariables = eqn.GetComponents();
	} else {
		sStateTracerMaxVariables = eqn.GetTracers();
	}

	info.sHaloElements = model.GetHaloElements();
	info.sComponents = sStateTracerMaxVariables;
	info.sMaxRElements = GetRElements() + 1;

	// Get the opposing direction
	GetOpposingDirection(
		boxSource.GetPanel(),
		boxTarget.GetPanel(),
		dir,
		info.dirOpposing,
		info.fReverseDirection,
		info.fFlippedCoordinate);

	// Determine the size of the boundary (number of elements along exterior
	// edge).  Used in computing the size of the send/recv buffers.
	if ((dir == Direction_Right) ||
		(dir == Direction_Top) ||
		(dir == Direction_Left) ||
		(dir == Direction_Bottom)
	) {
		info.sBoundarySize = ixSecond - ixFirst;
	} else {
		info.sBoundarySize = info.sHaloElements;
	}

	info.CalculateByteSize();

	if ((dir == Direction_TopRight) && (
		(ixFirst < boxSource.GetAInteriorBegin() + info.sBoundarySize - 1) ||
		(ixSecond < boxSource.GetBInteriorBegin() + info.sBoundarySize - 1)
	)) {
		_EXCEPTIONT("Insufficient interior elements to build "
			"diagonal connection.");
	}

	if ((dir == Direction_TopLeft) && (
		(ixFirst > boxSource.GetAInteriorEnd() - info.sBoundarySize) ||
		(ixSecond < boxSource.GetBInteriorBegin() + info.sBoundarySize - 1)
	)) {
		_EXCEPTIONT("Insufficient interior elements to build "
			"diagonal connection.");
	}

	if ((dir == Direction_BottomLeft) && (
		(ixFirst > boxSource.GetAInteriorEnd() - info.sBoundarySize) ||
		(ixSecond > boxSource.GetBInteriorEnd() - info.sBoundarySize)
	)) {
		_EXCEPTIONT("Insufficient interior elements to build "
			"diagonal connection.");
	}

	if ((dir == Direction_BottomRight) && (
		(ixFirst < boxSource.GetAInteriorBegin() + info.sBoundarySize - 1) ||
		(ixSecond > boxSource.GetBInteriorEnd() - info.sBoundarySize)
	)) {
		_EXCEPTIONT("Insufficient interior elements to build "
			"diagonal connection.");
	}

	// Add the exchange buffer information to the registry
	m_aExchangeBufferRegistry.Register(info);
}
Beispiel #7
0
void GridPatchCSGLL::InterpolateData(
	DataType eDataType,
	const DataArray1D<double> & dREta,
	const DataArray1D<double> & dAlpha,
	const DataArray1D<double> & dBeta,
	const DataArray1D<int> & iPatch,
	DataArray3D<double> & dInterpData,
	DataLocation eOnlyVariablesAt,
	bool fIncludeReferenceState,
	bool fConvertToPrimitive
) {
	if ((dAlpha.GetRows() != dBeta.GetRows()) ||
		(dAlpha.GetRows() != iPatch.GetRows())
	) {
		_EXCEPTIONT("Point vectors must have equivalent length.");
	}

	// Vector for storage interpolated points
	DataArray1D<double> dAInterpCoeffs(m_nHorizontalOrder);
	DataArray1D<double> dBInterpCoeffs(m_nHorizontalOrder);
	DataArray1D<double> dADiffCoeffs(m_nHorizontalOrder);
	DataArray1D<double> dBDiffCoeffs(m_nHorizontalOrder);
	DataArray1D<double> dAInterpPt(m_nHorizontalOrder);

	// Physical constants
	const PhysicalConstants & phys = m_grid.GetModel().GetPhysicalConstants();

	// Perform interpolation on all variables
	int nComponents = 0;
	int nRElements = m_grid.GetRElements();

	// Discretization type
	Grid::VerticalDiscretization eVerticalDiscType =
		m_grid.GetVerticalDiscretization();

	// State Data: Perform interpolation on all variables
	if (eDataType == DataType_State) {
		nComponents = m_datavecStateNode[0].GetSize(0);
		nRElements = m_grid.GetRElements() + 1;

	// Tracer Data: Perform interpolation on all variables
	} else if (eDataType == DataType_Tracers) {
		nComponents = m_datavecTracers[0].GetSize(0);

	// Topography Data
	} else if (eDataType == DataType_Topography) {
		nComponents = 1;
		nRElements = 1;

	// Vorticity Data
	} else if (eDataType == DataType_Vorticity) {
		nComponents = 1;

	// Divergence Data
	} else if (eDataType == DataType_Divergence) {
		nComponents = 1;

	// Temperature Data
	} else if (eDataType == DataType_Temperature) {
		nComponents = 1;

	// Surface Pressure Data
	} else if (eDataType == DataType_SurfacePressure) {
		nComponents = 1;
		nRElements = 1;

	// 2D User Data
	} else if (eDataType == DataType_Auxiliary2D) {
		nComponents = m_dataUserData2D.GetSize(0);
		nRElements = 1;

	} else {
		_EXCEPTIONT("Invalid DataType");
	}

	// Buffer storage in column
	DataArray1D<double> dColumnDataOut(dREta.GetRows());

	// Loop through all components
	for (int c = 0; c < nComponents; c++) {

		DataLocation eDataLocation = DataLocation_Node;

		if (eDataType == DataType_State) {
			eDataLocation = m_grid.GetVarLocation(c);

			// Exclude variables not at the specified DataLocation
			if ((eOnlyVariablesAt != DataLocation_None) &&
			    (eOnlyVariablesAt != eDataLocation)
			) {
				continue;
			}

			// Adjust RElements depending on state data location
			if (eDataLocation == DataLocation_Node) {
				nRElements = m_grid.GetRElements();
			} else if (eDataLocation == DataLocation_REdge) {
				nRElements = m_grid.GetRElements() + 1;
			} else {
				_EXCEPTIONT("Invalid DataLocation");
			}
		}

		// Vertical interpolation operator
		LinearColumnInterpFEM opInterp;

		if (nRElements != 1) {

			// Finite element interpolation
			if (eVerticalDiscType ==
				Grid::VerticalDiscretization_FiniteElement
			) {
				if (eDataLocation == DataLocation_Node) {
					opInterp.Initialize(
						LinearColumnInterpFEM::InterpSource_Levels,
						m_nVerticalOrder,
						m_grid.GetREtaLevels(),
						m_grid.GetREtaInterfaces(),
						dREta);

				} else if (eDataLocation == DataLocation_REdge) {
					opInterp.Initialize(
						LinearColumnInterpFEM::InterpSource_Interfaces,
						m_nVerticalOrder,
						m_grid.GetREtaLevels(),
						m_grid.GetREtaInterfaces(),
						dREta);

				} else {
					_EXCEPTIONT("Invalid DataLocation");
				}

			// Finite volume interpolation
			} else if (
				eVerticalDiscType ==
				Grid::VerticalDiscretization_FiniteVolume
			) {
				if (eDataLocation == DataLocation_Node) {
					opInterp.Initialize(
						LinearColumnInterpFEM::InterpSource_Levels,
						1,
						m_grid.GetREtaLevels(),
						m_grid.GetREtaInterfaces(),
						dREta);

				} else if (eDataLocation == DataLocation_REdge) {
					opInterp.Initialize(
						LinearColumnInterpFEM::InterpSource_Interfaces,
						1,
						m_grid.GetREtaLevels(),
						m_grid.GetREtaInterfaces(),
						dREta);

				} else {
					_EXCEPTIONT("Invalid DataLocation");
				}

			// Invalid vertical discretization type
			} else {
				_EXCEPTIONT("Invalid VerticalDiscretization");
			}

		} else {
			opInterp.InitializeIdentity(1);
		}

		// Buffer storage in column
		DataArray1D<double> dColumnData(nRElements);

		// Get a pointer to the 3D data structure
		DataArray3D<double> pData;
		DataArray3D<double> pDataRef;

		pData.SetSize(
			nRElements,
			m_box.GetATotalWidth(),
			m_box.GetBTotalWidth());

		pDataRef.SetSize(
			nRElements,
			m_box.GetATotalWidth(),
			m_box.GetBTotalWidth());

		if (eDataType == DataType_State) {
			if (eDataLocation == DataLocation_Node) {
				pData.AttachToData(&(m_datavecStateNode[0][c][0][0][0]));
				pDataRef.AttachToData(&(m_dataRefStateNode[c][0][0][0]));
			} else if (eDataLocation == DataLocation_REdge) {
				pData.AttachToData(&(m_datavecStateREdge[0][c][0][0][0]));
				pDataRef.AttachToData(&(m_dataRefStateREdge[c][0][0][0]));
			} else {
				_EXCEPTIONT("Invalid DataLocation");
			}

		} else if (eDataType == DataType_Tracers) {
			pData.AttachToData(&(m_datavecTracers[0][c][0][0][0]));

		} else if (eDataType == DataType_Topography) {
			pData.AttachToData(&(m_dataTopography[0][0]));

		} else if (eDataType == DataType_Vorticity) {
			pData.AttachToData(&(m_dataVorticity[0][0][0]));

		} else if (eDataType == DataType_Divergence) {
			pData.AttachToData(&(m_dataDivergence[0][0][0]));

		} else if (eDataType == DataType_Temperature) {
			pData.AttachToData(&(m_dataTemperature[0][0][0]));

		} else if (eDataType == DataType_SurfacePressure) {
			pData.AttachToData(&(m_dataSurfacePressure[0][0]));

		} else if (eDataType == DataType_Auxiliary2D) {
			pData.AttachToData(&(m_dataUserData2D[c][0][0]));
		}

		// Loop throught all points
		for (int i = 0; i < dAlpha.GetRows(); i++) {

			// Element index
			if (iPatch[i] != GetPatchIndex()) {
				continue;
			}

			// Verify point lies within domain of patch
			const double Eps = 1.0e-10;
			if ((dAlpha[i] < m_dAEdge[m_box.GetAInteriorBegin()] - Eps) ||
				(dAlpha[i] > m_dAEdge[m_box.GetAInteriorEnd()] + Eps) ||
				(dBeta[i] < m_dBEdge[m_box.GetBInteriorBegin()] - Eps) ||
				(dBeta[i] > m_dBEdge[m_box.GetBInteriorEnd()] + Eps)
			) {
				_EXCEPTIONT("Point out of range");
			}

			// Determine finite element index
			int iA =
				(dAlpha[i] - m_dAEdge[m_box.GetAInteriorBegin()])
					/ GetElementDeltaA();

			int iB =
				(dBeta[i] - m_dBEdge[m_box.GetBInteriorBegin()])
					/ GetElementDeltaB();

			// Bound the index within the element
			if (iA < 0) {
				iA = 0;
			}
			if (iA >= (m_box.GetAInteriorWidth() / m_nHorizontalOrder)) {
				iA = m_box.GetAInteriorWidth() / m_nHorizontalOrder - 1;
			}
			if (iB < 0) {
				iB = 0;
			}
			if (iB >= (m_box.GetBInteriorWidth() / m_nHorizontalOrder)) {
				iB = m_box.GetBInteriorWidth() / m_nHorizontalOrder - 1;
			}

			iA = m_box.GetHaloElements() + iA * m_nHorizontalOrder;
			iB = m_box.GetHaloElements() + iB * m_nHorizontalOrder;

			// Compute interpolation coefficients
			PolynomialInterp::LagrangianPolynomialCoeffs(
				m_nHorizontalOrder,
				&(m_dAEdge[iA]),
				dAInterpCoeffs,
				dAlpha[i]);

			PolynomialInterp::LagrangianPolynomialCoeffs(
				m_nHorizontalOrder,
				&(m_dBEdge[iB]),
				dBInterpCoeffs,
				dBeta[i]);

			// Perform interpolation on all levels
			for (int k = 0; k < nRElements; k++) {

				dColumnData[k] = 0.0;

				// Rescale vertical velocity
				const int WIx = 3;
				if ((c == WIx) && (fConvertToPrimitive)) {
					if (m_grid.GetVarLocation(WIx) == DataLocation_REdge) {
						for (int m = 0; m < m_nHorizontalOrder; m++) {
						for (int n = 0; n < m_nHorizontalOrder; n++) {
							dColumnData[k] +=
								  dAInterpCoeffs[m]
								* dBInterpCoeffs[n]
								* pData[k][iA+m][iB+n]
								/ m_dataDerivRREdge[k][iA][iB][2];
						}
						}

					} else {
						for (int m = 0; m < m_nHorizontalOrder; m++) {
						for (int n = 0; n < m_nHorizontalOrder; n++) {
							dColumnData[k] +=
								  dAInterpCoeffs[m]
								* dBInterpCoeffs[n]
								* pData[k][iA+m][iB+n]
								/ m_dataDerivRNode[k][iA][iB][2];
						}
						}
					}

				} else {
					for (int m = 0; m < m_nHorizontalOrder; m++) {
					for (int n = 0; n < m_nHorizontalOrder; n++) {
						dColumnData[k] +=
							  dAInterpCoeffs[m]
							* dBInterpCoeffs[n]
							* pData[k][iA+m][iB+n];
					}
					}
				}

				// Do not include the reference state
				if ((eDataType == DataType_State) &&
					(!fIncludeReferenceState)
				) {
					for (int m = 0; m < m_nHorizontalOrder; m++) {
					for (int n = 0; n < m_nHorizontalOrder; n++) {
						dColumnData[k] -=
							  dAInterpCoeffs[m]
							* dBInterpCoeffs[n]
							* pDataRef[k][iA+m][iB+n];
					}
					}
				}
			}

			// Interpolate vertically
			opInterp.Apply(
				&(dColumnData[0]),
				&(dColumnDataOut[0]));

			// Store data
			for (int k = 0; k < dREta.GetRows(); k++) {
				dInterpData[c][k][i] = dColumnDataOut[k];
			}

		}
	}

	// Convert to primitive variables
	if ((eDataType == DataType_State) && (fConvertToPrimitive)) {
		for (int i = 0; i < dAlpha.GetRows(); i++) { 
			if (iPatch[i] != GetPatchIndex()) {
				continue;
			}

			for (int k = 0; k < dREta.GetRows(); k++) {
				double dUalpha =
					dInterpData[0][k][i] / phys.GetEarthRadius();
				double dUbeta =
					dInterpData[1][k][i] / phys.GetEarthRadius();

				CubedSphereTrans::CoVecTransRLLFromABP(
					tan(dAlpha[i]),
					tan(dBeta[i]),
					GetPatchBox().GetPanel(),
					dUalpha,
					dUbeta,
					dInterpData[0][k][i],
					dInterpData[1][k][i]);
			}
		}
	}
}