void OutputManager::PerformOutput(
	const Time & time
) {
	// Open the file
	if (!m_fIsFileOpen) {
		std::string strActiveFileName;
		GetFileName(time, strActiveFileName);
		m_fIsFileOpen = OpenFile(strActiveFileName);

		if (!m_fIsFileOpen) {
			_EXCEPTION1("Unable to open file \"%s\"",
				strActiveFileName.c_str());
		}
	}

	// Output
	Output(time);
	m_ixOutputTime ++;

	// Check if time limit is reached
	if (m_ixOutputTime == m_nOutputsPerFile) {
		CloseFile();
		m_fIsFileOpen = false;
		m_ixOutputFile ++;
		m_ixOutputTime = 0;
	}
}
Example #2
0
void ExchangeBuffer::Reset() {
	if (m_dSendBuffer.GetByteSize() < sizeof(MessageHeader)) {
		_EXCEPTION1("Invalid ExchangeBuffer send buffer (%i)",
			m_dSendBuffer.GetByteSize());
	}
	if (sizeof(MessageHeader) % sizeof(double) != 0) {
		_EXCEPTIONT("sizeof(MessageHeader) % sizeof(double) != 0");
	}

	// Store ExchangeBuffer::MessageHeader
	GetSendMessageHeader((MessageHeader *)(&(m_dSendBuffer[0])));

	// Set read and write indices to just beyond the MessageHeader
	m_ixRecvBuffer = sizeof(MessageHeader) / sizeof(double);
	m_ixSendBuffer = sizeof(MessageHeader) / sizeof(double);
}
GridSpacingGaussLobatto::GridSpacingGaussLobatto(
	double dDeltaElement,
	double dZeroCoord,
	int nOrder
) :
	GridSpacing(dDeltaElement, dZeroCoord),
	m_nOrder(nOrder)
{
	// Check order
	if (m_nOrder < 2) {
		_EXCEPTION1("Invalid order of accuracy %i (Order < 2)", m_nOrder);
	}

	// Obtain GLL nodes
	GaussLobattoQuadrature::GetPoints(
		nOrder, 0.0, dDeltaElement, m_dG, m_dW);
}
///	<summary>
///		Load in the contents of a text file containing one filename per
///		line and store in a vector of strings.
///	</summary>
void GetInputFileList(
	const std::string & strInputFileList,
	std::vector<std::string> & vecInputFiles
) {
	FILE * fp = fopen(strInputFileList.c_str(), "r");

	char szBuffer[1024];
	for (;;) {
		fgets(szBuffer, 1024, fp);

		if (feof(fp)) {
			break;
		}

		// Remove end-of-line characters
		for (;;) {
			int nLen = strlen(szBuffer);
			if ((szBuffer[nLen-1] == '\n') ||
				(szBuffer[nLen-1] == '\r') ||
				(szBuffer[nLen-1] == ' ')
			) {
				szBuffer[nLen-1] = '\0';
				continue;
			}
			break;
		}

		vecInputFiles.push_back(szBuffer);
	}

	if (vecInputFiles.size() == 0) {
		_EXCEPTION1("No files found in file \"%s\"", strInputFileList.c_str());
	}

	fclose(fp);
}
bool OutputManagerComposite::OpenFile(
    const std::string & strFileName
) {
#ifdef USE_MPI
    // Determine processor rank
    int nRank;
    MPI_Comm_rank(MPI_COMM_WORLD, &nRank);

    // Open file at root
    if (nRank == 0) {

        // Check for existing file
        if (m_ofsActiveOutput.is_open()) {
            _EXCEPTIONT("Restart file already open");
        }

        // Open new binary output stream
        std::string strRestartFileName = strFileName + ".restart.dat";
        m_ofsActiveOutput.open(
            strRestartFileName.c_str(), std::ios::binary | std::ios::out);

        if (!m_ofsActiveOutput) {
            _EXCEPTION1("Error opening output file \"%s\"",
                        strRestartFileName.c_str());
        }
    }

    // Wait for all processes to complete
    MPI_Barrier(MPI_COMM_WORLD);

    return true;
#else
    _EXCEPTIONT("Not implemented without USE_MPI");
#endif

}
void CubedSphereTrans::CoVecTransRLLFromABP(
	double dX,
	double dY,
	int nP,
	double dUalpha,
	double dUbeta,
	double & dUlon,
	double & dUlat
) {
	double dDelta2 = 1.0 + dX * dX + dY * dY;
	double dRadius;
	double dRadius2;

	double lat;

	switch (nP) {
		// Equatorial panels
		case 0:
		case 1:
		case 2:
		case 3:
			// Calculate new vector components
			dUlon =
				  dDelta2 / (1.0 + dX * dX) * dUalpha
				+ dDelta2 * dX * dY / (1.0 + dX * dX) / (1.0 + dY * dY) * dUbeta;
			dUlat =
				  dDelta2 / sqrt(1.0 + dX * dX) / (1.0 + dY * dY) * dUbeta;

			// Convert spherical coords to geometric basis
			lat = atan(dY / sqrt(1.0 + dX * dX));
			dUlon *= cos(lat);

			break;

		// North polar panel
		case 4:
			// Calculate new vector components
			dRadius2 = (dX * dX + dY * dY);
			dRadius = sqrt(dRadius2);

			dUlon =
				- dDelta2 * dY / (1.0 + dX * dX) / dRadius2 * dUalpha
				+ dDelta2 * dX / (1.0 + dY * dY) / dRadius2 * dUbeta;

			dUlat =
				- dDelta2 * dX / (1.0 + dX * dX) / dRadius * dUalpha
				- dDelta2 * dY / (1.0 + dY * dY) / dRadius * dUbeta;

			// Convert spherical coords to geometric basis
			lat = 0.5 * M_PI - atan(sqrt(dX * dX + dY * dY));
			dUlon *= cos(lat);

			break;

		// South polar panel
		case 5:
			// Calculate new vector components
			dRadius2 = (dX * dX + dY * dY);
			dRadius = sqrt(dRadius2);

			dUlon =
				+ dDelta2 * dY / (1.0 + dX * dX) / dRadius2 * dUalpha
				- dDelta2 * dX / (1.0 + dY * dY) / dRadius2 * dUbeta;

			dUlat =
				+ dDelta2 * dX / (1.0 + dX * dX) / dRadius * dUalpha
				+ dDelta2 * dY / (1.0 + dY * dY) / dRadius * dUbeta;

			// Convert spherical coords to geometric basis
			lat = 0.5 * M_PI - atan(sqrt(dX * dX + dY * dY));
			dUlon *= cos(lat);

			break;

		// Invalid panel
		default:
			_EXCEPTION1(
				"Invalid nP coordinate.  Given: %d, Expected: [0-5].\n", nP);
	}
}
void Connectivity::BuildFluxConnectivity() {

	// PatchBox
	const PatchBox & box = m_patch.GetPatchBox();

	// Allocate space for edges
	m_vecExteriorEdge[0].resize(box.GetBTotalWidth(), NULL);
	m_vecExteriorEdge[1].resize(box.GetATotalWidth(), NULL);
	m_vecExteriorEdge[2].resize(box.GetBTotalWidth(), NULL);
	m_vecExteriorEdge[3].resize(box.GetATotalWidth(), NULL);
	m_vecExteriorEdge[4].resize(1, NULL);
	m_vecExteriorEdge[5].resize(1, NULL);
	m_vecExteriorEdge[6].resize(1, NULL);
	m_vecExteriorEdge[7].resize(1, NULL);

	// Loop over all exterior edges, hook up pointers to ExteriorNeighbors
	for (int n = 0; n < m_vecExteriorNeighbors.size(); n++) {

		ExteriorNeighbor * pNeighbor = m_vecExteriorNeighbors[n];

		int iDir = static_cast<int>(pNeighbor->m_dir);

		// Right or Left side of this PatchBox
		if ((pNeighbor->m_dir == Direction_Right) || 
		    (pNeighbor->m_dir == Direction_Left)
		) {
			int j = pNeighbor->m_ixFirst;
			for (; j < pNeighbor->m_ixSecond; j++) {
				if ((j < box.GetBInteriorBegin()) ||
					(j >= box.GetBInteriorEnd())
				) {
					_EXCEPTIONT("Edge index out of range");
				}

				m_vecExteriorEdge[iDir][j] = pNeighbor;
			}

		// Top or Bottom side of this PatchBox
		} else if (
		    (pNeighbor->m_dir == Direction_Top) ||
		    (pNeighbor->m_dir == Direction_Bottom)
		) {
			int i = pNeighbor->m_ixFirst;
			for (; i < pNeighbor->m_ixSecond; i++) {
				if ((i < box.GetAInteriorBegin()) ||
					(i >= box.GetAInteriorEnd())
				) {
					_EXCEPTIONT("Edge index out of range");
				}

				m_vecExteriorEdge[iDir][i] = pNeighbor;
			}

		// Corners of this PatchBox
		} else if (
		    (pNeighbor->m_dir == Direction_TopRight) ||
		    (pNeighbor->m_dir == Direction_TopLeft) ||
		    (pNeighbor->m_dir == Direction_BottomRight) ||
		    (pNeighbor->m_dir == Direction_BottomLeft)
		) {
			if (m_vecExteriorEdge[iDir][0] != NULL) {
				_EXCEPTION1("Corner patch %i already set", iDir);
			}
			m_vecExteriorEdge[iDir][0] = pNeighbor;

		} else {
			_EXCEPTIONT("Invalid direction");
		}
	}
}
void CubedSphereTrans::RLLFromXYP(
	double dX,
	double dY,
	int nP,
	double &lon,
	double &lat
) {
	switch (nP) {
		// Equatorial panel 1
		case 0:
			lon = atan(dX);
			lat = atan(dY / sqrt(1.0 + dX * dX));
			break;

		// Equatorial panel 2
		case 1:
			lon = atan(dX) + 0.5 * M_PI;
			lat = atan(dY / sqrt(1.0 + dX * dX));
			break;

		// Equatorial panel 3
		case 2:
			lon = atan(dX) + M_PI;
			lat = atan(dY / sqrt(1.0 + dX * dX));
			break;

		// Equatorial panel 4
		case 3:
			lon = atan(dX) + 1.5 * M_PI;
			lat = atan(dY / sqrt(1.0 + dX * dX));
			break;

		// North polar panel
		case 4:
			if (fabs(dX) > DBL_EPSILON) {
				lon = atan2(dX, -dY);
			} else if (dY <= 0.0) {
				lon = 0.0;
			} else {
				lon = M_PI;
			}
			lat = 0.5 * M_PI - atan(sqrt(dX * dX + dY * dY));
			break;

		// South polar panel
		case 5:
			if (fabs(dX) > DBL_EPSILON) {
				lon = atan2(dX, dY);
			} else if (dY > 0.0) {
				lon = 0.0;
			} else {
				lon = M_PI;
			}
			lat = -0.5 * M_PI + atan(sqrt(dX * dX + dY * dY));
			break;

		// Invalid panel
		default:
			_EXCEPTION1(
				"Invalid nP coordinate.  Given: %d, Expected: [0-5].\n", nP);
	}

	// Map to the interval [0, 2 pi]
	if (lon < 0.0) {
		lon += 2.0 * M_PI;
	}
}
void CubedSphereTrans::CoVecTransABPFromRLL(
	double dX,
	double dY,
	int nP,
	double dUlon,
	double dUlat,
	double & dUalpha,
	double & dUbeta
) {
	double dDelta2 = 1.0 + dX * dX + dY * dY;
	double dRadius;

	double lat;

	if ((nP > 3) && (fabs(dX) < 1.0e-13) && (fabs(dY) < 1.0e-13)) {
		if (nP == 4) {
			dUalpha = dUlon;
		} else {
			dUalpha = - dUlon;
		}
		dUbeta = dUlat;
		return;
	}

	switch (nP) {
		// Equatorial panels
		case 0:
		case 1:
		case 2:
		case 3:
			// Convert Ulon from geometric basis
			lat = atan(dY / sqrt(1.0 + dX * dX));
			dUlon = dUlon / cos(lat);

			// Calculate vector component
			dUalpha =
				  (1.0 + dX * dX) / dDelta2 * dUlon
				- dX * dY * sqrt(1.0 + dX * dX) / dDelta2 * dUlat;
			dUbeta = 
				sqrt(1.0 + dX * dX) * (1.0 + dY * dY) / dDelta2 * dUlat;

			break;

		// North polar panel
		case 4:
			// Convert Ulon from geometric basis
			lat = 0.5 * M_PI - atan(sqrt(dX * dX + dY * dY));
			dUlon = dUlon / cos(lat);

			// Calculate vector component
			dRadius = sqrt(dX * dX + dY * dY);

			dUalpha = 
				- dY * (1.0 + dX * dX) / dDelta2 * dUlon
				- dX * (1.0 + dX * dX) / (dDelta2 * dRadius) * dUlat;

			dUbeta =
				+ dX * (1.0 + dY * dY) / dDelta2 * dUlon
				- dY * (1.0 + dY * dY) / (dDelta2 * dRadius) * dUlat;

			break;

		// South polar panel
		case 5:

			// Convert Ulon from geometric basis
			lat = -0.5 * M_PI + atan(sqrt(dX * dX + dY * dY));
			dUlon = dUlon / cos(lat);

			// Calculate vector component
			dRadius = sqrt(dX * dX + dY * dY);

			dUalpha = 
				+ dY * (1.0 + dX * dX) / dDelta2 * dUlon
				+ dX * (1.0 + dX * dX) / (dDelta2 * dRadius) * dUlat;

			dUbeta =
				- dX * (1.0 + dY * dY) / dDelta2 * dUlon
				+ dY * (1.0 + dY * dY) / (dDelta2 * dRadius) * dUlat;

			break;

		// Invalid panel
		default:
			_EXCEPTION1(
				"Invalid nP coordinate.  Given: %d, Expected: [0-5].\n", nP);
	}
}
void ParseLevelArray(
	const std::string & strLevels,
	std::vector<double> & vecLevels
) {
	int iLevelBegin = 0;
	int iLevelCurrent = 0;

	vecLevels.clear();

	if (strLevels == "") {
		return;
	}

	// Parse pressure levels
	bool fRangeMode = false;
	for (;;) {
		if ((iLevelCurrent >= strLevels.length()) ||
			(strLevels[iLevelCurrent] == ',') ||
			(strLevels[iLevelCurrent] == ' ') ||
			(strLevels[iLevelCurrent] == ':')
		) {
			// Range mode
			if ((!fRangeMode) &&
				(strLevels[iLevelCurrent] == ':')
			) {
				if (vecLevels.size() != 0) {
					_EXCEPTIONT("Invalid set of pressure levels");
				}
				fRangeMode = true;
			}
			if (fRangeMode) {
				if ((strLevels[iLevelCurrent] != ':') &&
					(iLevelCurrent < strLevels.length())
				) {
					_EXCEPTION1("Invalid character in pressure range (%c)",
						strLevels[iLevelCurrent]);
				}
			}

			if (iLevelCurrent == iLevelBegin) {
				if (iLevelCurrent >= strLevels.length()) {
					break;
				}

				continue;
			}

			std::string strPressureLevelSubStr = 
				strLevels.substr(
					iLevelBegin, iLevelCurrent - iLevelBegin);

			vecLevels.push_back(atof(strPressureLevelSubStr.c_str()));
			
			iLevelBegin = iLevelCurrent + 1;
		}

		iLevelCurrent++;
	}

	// Range mode -- repopulate array
	if (fRangeMode) {
		if (vecLevels.size() != 3) {
			_EXCEPTIONT("Exactly three pressure level entries required "
				"for range mode");
		}
		double dLevelBegin = vecLevels[0];
		double dLevelStep = vecLevels[1];
		double dLevelEnd = vecLevels[2];

		if (dLevelStep == 0.0) {
			_EXCEPTIONT("Level step size cannot be zero");
		}
		if ((dLevelEnd - dLevelBegin) / dLevelStep > 10000.0) {
			_EXCEPTIONT("Too many levels in range (limit 10000)");
		}
		if ((dLevelEnd - dLevelBegin) / dLevelStep < 0.0) {
			_EXCEPTIONT("Sign mismatch in level step");
		}

		vecLevels.clear();
		for (int i = 0 ;; i++) {
			double dLevel = dLevelBegin + static_cast<double>(i) * dLevelStep;

			if ((dLevelStep > 0.0) && (dLevel > dLevelEnd)) {
				break;
			}
			if ((dLevelStep < 0.0) && (dLevel < dLevelEnd)) {
				break;
			}

			vecLevels.push_back(dLevel);
		}
	}
}
int main(int argc, char ** argv) {

	MPI_Init(&argc, &argv);

	NcError error(NcError::silent_nonfatal);

try {

	// Input filename
	std::string strInputFile;

	// Output filename
	std::string strOutputFile;

	// Separate topography file
	std::string strTopographyFile;

	// List of variables to extract
	std::string strVariables;

	// Extract geopotential height
	bool fGeopotentialHeight;

	// Pressure levels to extract
	std::string strPressureLevels;

	// Height levels to extract
	std::string strHeightLevels;

	// Extract variables at the surface
	bool fExtractSurface;

	// Extract total energy
	bool fExtractTotalEnergy;

	// Parse the command line
	BeginCommandLine()
		CommandLineString(strInputFile, "in", "");
		CommandLineString(strOutputFile, "out", "");
		CommandLineString(strVariables, "var", "");
		CommandLineBool(fGeopotentialHeight, "output_z");
		CommandLineBool(fExtractTotalEnergy, "output_energy");
		CommandLineString(strPressureLevels, "p", "");
		CommandLineString(strHeightLevels, "z", "");
		CommandLineBool(fExtractSurface, "surf");

		ParseCommandLine(argc, argv);
	EndCommandLine(argv)

	AnnounceBanner();

	// Check command line arguments
	if (strInputFile == "") {
		_EXCEPTIONT("No input file specified");
	}
	if (strOutputFile == "") {
		_EXCEPTIONT("No output file specified");
	}
	if (strVariables == "") {
		_EXCEPTIONT("No variables specified");
	}

	// Parse variable string
	std::vector< std::string > vecVariableStrings;

	ParseVariableList(strVariables, vecVariableStrings);

	// Check variables
	if (vecVariableStrings.size() == 0) {
		_EXCEPTIONT("No variables specified");
	}

	// Parse pressure level string
	std::vector<double> vecPressureLevels;

	ParseLevelArray(strPressureLevels, vecPressureLevels);

	int nPressureLevels = (int)(vecPressureLevels.size());

	for (int k = 0; k < nPressureLevels; k++) {
		if (vecPressureLevels[k] <= 0.0) {
			_EXCEPTIONT("Non-positive pressure values not allowed");
		}
	}

	// Parse height level string
	std::vector<double> vecHeightLevels;

	ParseLevelArray(strHeightLevels, vecHeightLevels);

	int nHeightLevels = (int)(vecHeightLevels.size());

	// Check pressure levels
	if ((nPressureLevels == 0) &&
		(nHeightLevels == 0) &&
		(!fExtractSurface)
	) {
		_EXCEPTIONT("No pressure / height levels to process");
	}

	// Open input file
	AnnounceStartBlock("Loading input file");
	NcFile ncdf_in(strInputFile.c_str(), NcFile::ReadOnly);
	if (!ncdf_in.is_valid()) {
		_EXCEPTION1("Unable to open file \"%s\" for reading",
			strInputFile.c_str());
	}

	// Load time array
	Announce("Time");
	NcVar * varTime = ncdf_in.get_var("time");
	if (varTime == NULL) {
		_EXCEPTION1("File \"%s\" does not contain variable \"time\"",
			strInputFile.c_str());
	}
	int nTime = varTime->get_dim(0)->size();

	DataArray1D<double> dTime(nTime);
	varTime->set_cur((long)0);
	varTime->get(&(dTime[0]), nTime);

	// Load latitude array
	Announce("Latitude");
	NcVar * varLat = ncdf_in.get_var("lat");
	if (varLat == NULL) {
		_EXCEPTION1("File \"%s\" does not contain variable \"lat\"",
			strInputFile.c_str());
	}
	int nLat = varLat->get_dim(0)->size();

	DataArray1D<double> dLat(nLat);
	varLat->set_cur((long)0);
	varLat->get(&(dLat[0]), nLat);

	// Load longitude array
	Announce("Longitude");
	NcVar * varLon = ncdf_in.get_var("lon");
	if (varLon == NULL) {
		_EXCEPTION1("File \"%s\" does not contain variable \"lon\"",
			strInputFile.c_str());
	}
	int nLon = varLon->get_dim(0)->size();

	DataArray1D<double> dLon(nLon);
	varLon->set_cur((long)0);
	varLon->get(&(dLon[0]), nLon);

	// Load level array
	Announce("Level");
	NcVar * varLev = ncdf_in.get_var("lev");
	if (varLev == NULL) {
		_EXCEPTION1("File \"%s\" does not contain variable \"lev\"",
			strInputFile.c_str());
	}
	int nLev = varLev->get_dim(0)->size();

	DataArray1D<double> dLev(nLev);
	varLev->set_cur((long)0);
	varLev->get(&(dLev[0]), nLev);

	// Load level interface array
	Announce("Interface");
	NcVar * varILev = ncdf_in.get_var("ilev");
	int nILev = 0;
	DataArray1D<double> dILev;
	if (varILev == NULL) {
		Announce("Warning: Variable \"ilev\" not found");
	} else {
		nILev = varILev->get_dim(0)->size();
		if (nILev != nLev + 1) {
			_EXCEPTIONT("Variable \"ilev\" must have size lev+1");
		}
		dILev.Allocate(nILev);
		varILev->set_cur((long)0);
		varILev->get(&(dILev[0]), nILev);
	}

	// Load topography
	Announce("Topography");
	NcVar * varZs = ncdf_in.get_var("Zs");
	if (varZs == NULL) {
		_EXCEPTION1("File \"%s\" does not contain variable \"Zs\"",
			strInputFile.c_str());
	}

	DataArray2D<double> dZs(nLat, nLon);
	varZs->set_cur((long)0, (long)0);
	varZs->get(&(dZs[0][0]), nLat, nLon);

	AnnounceEndBlock("Done");

	// Open output file
	AnnounceStartBlock("Constructing output file");

	NcFile ncdf_out(strOutputFile.c_str(), NcFile::Replace);
	if (!ncdf_out.is_valid()) {
		_EXCEPTION1("Unable to open file \"%s\" for writing",
			strOutputFile.c_str());
	}

	CopyNcFileAttributes(&ncdf_in, &ncdf_out);

	// Output time array
	Announce("Time");
	NcDim * dimOutTime = ncdf_out.add_dim("time");
	NcVar * varOutTime = ncdf_out.add_var("time", ncDouble, dimOutTime);
	varOutTime->set_cur((long)0);
	varOutTime->put(&(dTime[0]), nTime);

	CopyNcVarAttributes(varTime, varOutTime);

	// Output pressure array
	NcDim * dimOutP = NULL;
	NcVar * varOutP = NULL;
	if (nPressureLevels > 0) {
		Announce("Pressure");
		dimOutP = ncdf_out.add_dim("p", nPressureLevels);
		varOutP = ncdf_out.add_var("p", ncDouble, dimOutP);
		varOutP->set_cur((long)0);
		varOutP->put(&(vecPressureLevels[0]), nPressureLevels);
	}

	// Output height array
	NcDim * dimOutZ = NULL;
	NcVar * varOutZ = NULL;
	if (nHeightLevels > 0) {
		Announce("Height");
		dimOutZ = ncdf_out.add_dim("z", nHeightLevels);
		varOutZ = ncdf_out.add_var("z", ncDouble, dimOutZ);
		varOutZ->set_cur((long)0);
		varOutZ->put(&(vecHeightLevels[0]), nHeightLevels);
	}

	// Output latitude and longitude array
	Announce("Latitude");
	NcDim * dimOutLat = ncdf_out.add_dim("lat", nLat);
	NcVar * varOutLat = ncdf_out.add_var("lat", ncDouble, dimOutLat);
	varOutLat->set_cur((long)0);
	varOutLat->put(&(dLat[0]), nLat);

	CopyNcVarAttributes(varLat, varOutLat);

	Announce("Longitude");
	NcDim * dimOutLon = ncdf_out.add_dim("lon", nLon);
	NcVar * varOutLon = ncdf_out.add_var("lon", ncDouble, dimOutLon);
	varOutLon->set_cur((long)0);
	varOutLon->put(&(dLon[0]), nLon);

	CopyNcVarAttributes(varLon, varOutLon);

	// Output topography
	Announce("Topography");
	NcVar * varOutZs = ncdf_out.add_var(
		"Zs", ncDouble, dimOutLat, dimOutLon);

	varOutZs->set_cur((long)0, (long)0);
	varOutZs->put(&(dZs[0][0]), nLat, nLon);

	AnnounceEndBlock("Done");

	// Done
	AnnounceEndBlock("Done");

	// Load all variables
	Announce("Loading variables");

	std::vector<NcVar *> vecNcVar;
	for (int v = 0; v < vecVariableStrings.size(); v++) {
		vecNcVar.push_back(ncdf_in.get_var(vecVariableStrings[v].c_str()));
		if (vecNcVar[v] == NULL) {
			_EXCEPTION1("Unable to load variable \"%s\" from file",
				vecVariableStrings[v].c_str());
		}
	}

	// Physical constants
	Announce("Initializing thermodynamic variables");

	NcAtt * attEarthRadius = ncdf_in.get_att("earth_radius");
	double dEarthRadius = attEarthRadius->as_double(0);

	NcAtt * attRd = ncdf_in.get_att("Rd");
	double dRd = attRd->as_double(0);

	NcAtt * attCp = ncdf_in.get_att("Cp");
	double dCp = attCp->as_double(0);

	double dGamma = dCp / (dCp - dRd);

	NcAtt * attP0 = ncdf_in.get_att("P0");
	double dP0 = attP0->as_double(0);

	double dPressureScaling = dP0 * std::pow(dRd / dP0, dGamma);

	NcAtt * attZtop = ncdf_in.get_att("Ztop");
	double dZtop = attZtop->as_double(0);

	// Input data
	DataArray3D<double> dataIn(nLev, nLat, nLon);
	DataArray3D<double> dataInt(nILev, nLat, nLon);

	// Output data
	DataArray2D<double> dataOut(nLat, nLon);

	// Pressure in column
	DataArray1D<double> dataColumnP(nLev);

	// Height in column
	DataArray1D<double> dataColumnZ(nLev);
	DataArray1D<double> dataColumnIZ(nILev);

	// Column weights
	DataArray1D<double> dW(nLev);
	DataArray1D<double> dIW(nILev);

	// Loop through all times, pressure levels and variables
	AnnounceStartBlock("Interpolating");

	// Add energy variable
	NcVar * varEnergy;
	if (fExtractTotalEnergy) {
		varEnergy = ncdf_out.add_var("TE", ncDouble, dimOutTime);
	}

	// Create output pressure variables
	std::vector<NcVar *> vecOutNcVarP;
	if (nPressureLevels > 0) {
		for (int v = 0; v < vecVariableStrings.size(); v++) {
			vecOutNcVarP.push_back(
				ncdf_out.add_var(
					vecVariableStrings[v].c_str(), ncDouble,
						dimOutTime, dimOutP, dimOutLat, dimOutLon));

			// Copy attributes
			CopyNcVarAttributes(vecNcVar[v], vecOutNcVarP[v]);
		}
	}

	// Create output height variables
	std::vector<NcVar *> vecOutNcVarZ;
	if (nHeightLevels > 0) {
		for (int v = 0; v < vecVariableStrings.size(); v++) {
			std::string strVarName = vecVariableStrings[v];
			if (nPressureLevels > 0) {
				strVarName += "z";
			}
			vecOutNcVarZ.push_back(
				ncdf_out.add_var(
					strVarName.c_str(), ncDouble,
						dimOutTime, dimOutZ, dimOutLat, dimOutLon));

			// Copy attributes
			CopyNcVarAttributes(vecNcVar[v], vecOutNcVarZ[v]);
		}
	}

	// Create output surface variable
	std::vector<NcVar *> vecOutNcVarS;
	if (fExtractSurface) {
		for (int v = 0; v < vecVariableStrings.size(); v++) {
			std::string strVarName = vecVariableStrings[v];
			strVarName += "S";

			vecOutNcVarS.push_back(
				ncdf_out.add_var(
					strVarName.c_str(), ncDouble,
						dimOutTime, dimOutLat, dimOutLon));

			// Copy attributes
			CopyNcVarAttributes(vecNcVar[v], vecOutNcVarS[v]);
		}
	}

	// Loop over all times
	for (int t = 0; t < nTime; t++) {

		char szAnnounce[256];
		sprintf(szAnnounce, "Time %i", t); 
		AnnounceStartBlock(szAnnounce);

		// Rho
		DataArray3D<double> dataRho(nLev, nLat, nLon);

		NcVar * varRho = ncdf_in.get_var("Rho");
		if (varRho == NULL) {
			_EXCEPTIONT("Unable to load variable \"Rho\" from file");
		}
		varRho->set_cur(t, 0, 0, 0);
		varRho->get(&(dataRho[0][0][0]), 1, nLev, nLat, nLon);

		// Pressure
		DataArray3D<double> dataP(nLev, nLat, nLon);

		if (nPressureLevels != 0) {
			NcVar * varP = ncdf_in.get_var("P");
			if (varP == NULL) {
				_EXCEPTIONT("Unable to load variable \"P\" from file");
			}
			varP->set_cur(t, 0, 0, 0);
			varP->get(&(dataP[0][0][0]), 1, nLev, nLat, nLon);
		}
/*
		// Populate pressure array
		if (nPressureLevels > 0) {

			// Calculate pointwise pressure
			for (int k = 0; k < nLev; k++) {
			for (int i = 0; i < nLat; i++) {
			for (int j = 0; j < nLon; j++) {
				dataP[k][i][j] = dPressureScaling
					* exp(log(dataRho[k][i][j] * dataP[k][i][j]) * dGamma);
			}
			}
			}
		}
*/
		// Height everywhere
		DataArray3D<double> dataZ(nLev, nLat, nLon);
		DataArray3D<double> dataIZ;
		if (nILev != 0) {
			dataIZ.Allocate(nILev, nLat, nLon);
		}

		// Populate height array
		if ((nHeightLevels > 0) || (fGeopotentialHeight)) {
			for (int k = 0; k < nLev; k++) {
			for (int i = 0; i < nLat; i++) {
			for (int j = 0; j < nLon; j++) {
				dataZ[k][i][j] = dZs[i][j] + dLev[k] * (dZtop - dZs[i][j]);
			}
			}
			}

			for (int k = 0; k < nILev; k++) {
			for (int i = 0; i < nLat; i++) {
			for (int j = 0; j < nLon; j++) {
				dataIZ[k][i][j] = dZs[i][j] + dILev[k] * (dZtop - dZs[i][j]);
			}
			}
			}
		}

		// Loop through all pressure levels and variables
		for (int v = 0; v < vecNcVar.size(); v++) {

			bool fOnInterfaces = false;

			// Load in the data array
			vecNcVar[v]->set_cur(t, 0, 0, 0);

			if (vecNcVar[v]->get_dim(1)->size() == nLev) {
				vecNcVar[v]->get(&(dataIn[0][0][0]), 1, nLev, nLat, nLon);

				Announce("%s (n)", vecVariableStrings[v].c_str());

			} else if (vecNcVar[v]->get_dim(1)->size() == nILev) {
				vecNcVar[v]->get(&(dataInt[0][0][0]), 1, nILev, nLat, nLon);
				fOnInterfaces = true;

				Announce("%s (i)", vecVariableStrings[v].c_str());
			} else {
				_EXCEPTION1("Variable \"%s\" has invalid level dimension",
					vecVariableStrings[v].c_str());
			}

			// At the physical surface
			if (fExtractSurface) {

				if (fOnInterfaces) {
					for (int i = 0; i < nLat; i++) {
					for (int j = 0; j < nLon; j++) {
						dataOut[i][j] = dataInt[0][i][j];
					}
					}

				} else {

					int kBegin = 0;
					int kEnd = 3;

					PolynomialInterp::LagrangianPolynomialCoeffs(
						3, dLev, dW, 0.0);

					// Loop thorugh all latlon indices
					for (int i = 0; i < nLat; i++) {
					for (int j = 0; j < nLon; j++) {

						// Interpolate in the vertical
						dataOut[i][j] = 0.0;
						for (int k = kBegin; k < kEnd; k++) {
							dataOut[i][j] += dW[k] * dataIn[k][i][j];
						}
					}
					}
				}

				// Write variable
				vecOutNcVarS[v]->set_cur(t, 0, 0);
				vecOutNcVarS[v]->put(&(dataOut[0][0]), 1, nLat, nLon);

			}

			// Loop through all pressure levels
			for (int p = 0; p < nPressureLevels; p++) {

				// Loop thorugh all latlon indices
				for (int i = 0; i < nLat; i++) {
				for (int j = 0; j < nLon; j++) {

					// Store column pressure
					for (int k = 0; k < nLev; k++) {
						dataColumnP[k] = dataP[k][i][j];
					}

					// Find weights
					int kBegin = 0;
					int kEnd = 0;

					// On a pressure surface
					InterpolationWeightsLinear(
						vecPressureLevels[p],
						dataColumnP,
						kBegin,
						kEnd,
						dW);

					// Interpolate in the vertical
					dataOut[i][j] = 0.0;
					for (int k = kBegin; k < kEnd; k++) {
						dataOut[i][j] += dW[k] * dataIn[k][i][j];
					}

				}
				}

				// Write variable
				vecOutNcVarP[v]->set_cur(t, p, 0, 0);
				vecOutNcVarP[v]->put(&(dataOut[0][0]), 1, 1, nLat, nLon);
			}

			// Loop through all height levels
			for (int z = 0; z < nHeightLevels; z++) {

				// Loop thorugh all latlon indices
				for (int i = 0; i < nLat; i++) {
				for (int j = 0; j < nLon; j++) {

					// Find weights
					int kBegin = 0;
					int kEnd = 0;

					// Interpolate from levels to z surfaces
					if (!fOnInterfaces) {
						for (int k = 0; k < nLev; k++) {
							dataColumnZ[k] = dataZ[k][i][j];
						}

						InterpolationWeightsLinear(
							vecHeightLevels[z],
							dataColumnZ,
							kBegin,
							kEnd,
							dW);

						dataOut[i][j] = 0.0;
						for (int k = kBegin; k < kEnd; k++) {
							dataOut[i][j] += dW[k] * dataIn[k][i][j];
						}

					// Interpolate from interfaces to z surfaces
					} else {
						for (int k = 0; k < nILev; k++) {
							dataColumnIZ[k] = dataIZ[k][i][j];
						}

						InterpolationWeightsLinear(
							vecHeightLevels[z],
							dataColumnIZ,
							kBegin,
							kEnd,
							dIW);

						dataOut[i][j] = 0.0;
						for (int k = kBegin; k < kEnd; k++) {
							dataOut[i][j] += dIW[k] * dataInt[k][i][j];
						}
					}
				}
				}

				// Write variable
				vecOutNcVarZ[v]->set_cur(t, z, 0, 0);
				vecOutNcVarZ[v]->put(&(dataOut[0][0]), 1, 1, nLat, nLon);
			}
		}

		// Output geopotential height
		if (fGeopotentialHeight) {

			Announce("Geopotential height");

			// Output variables
			NcVar * varOutZ;
			NcVar * varOutZs;

			if (nPressureLevels > 0) {
				varOutZ = ncdf_out.add_var(
					"PHIZ", ncDouble, dimOutTime, dimOutP, dimOutLat, dimOutLon);
			}
			if (fExtractSurface) {
				varOutZs = ncdf_out.add_var(
					"PHIZS", ncDouble, dimOutTime, dimOutLat, dimOutLon);
			}

			// Interpolate onto pressure levels
			for (int p = 0; p < nPressureLevels; p++) {

				// Loop thorugh all latlon indices
				for (int i = 0; i < nLat; i++) {
				for (int j = 0; j < nLon; j++) {

					int kBegin = 0;
					int kEnd = 0;

					for (int k = 0; k < nLev; k++) {
						dataColumnP[k] = dataP[k][i][j];
					}

					InterpolationWeightsLinear(
						vecPressureLevels[p],
						dataColumnP,
						kBegin,
						kEnd,
						dW);

					// Interpolate in the vertical
					dataOut[i][j] = 0.0;
					for (int k = kBegin; k < kEnd; k++) {
						dataOut[i][j] += dW[k] * dataZ[k][i][j];
					}
				}
				}

				// Write variable
				varOutZ->set_cur(t, p, 0, 0);
				varOutZ->put(&(dataOut[0][0]), 1, 1, nLat, nLon);

			}

			// Interpolate onto the physical surface
			if (fExtractSurface) {

				int kBegin = 0;
				int kEnd = 3;

				PolynomialInterp::LagrangianPolynomialCoeffs(
					3, dLev, dW, 0.0);

				// Loop thorugh all latlon indices
				for (int i = 0; i < nLat; i++) {
				for (int j = 0; j < nLon; j++) {

					// Interpolate in the vertical
					dataOut[i][j] = 0.0;
					for (int k = kBegin; k < kEnd; k++) {
						dataOut[i][j] += dW[k] * dataZ[k][i][j];
					}
				}
				}

				// Write variable
				varOutZs->set_cur(t, 0, 0);
				varOutZs->put(&(dataOut[0][0]), 1, nLat, nLon);

			}
		}

		// Extract total energy
		if (fExtractTotalEnergy) {
			Announce("Total Energy");

			// Zonal velocity
			DataArray3D<double> dataU(nLev, nLat, nLon);

			NcVar * varU = ncdf_in.get_var("U");
			varU->set_cur(t, 0, 0, 0);
			varU->get(&(dataU[0][0][0]), 1, nLev, nLat, nLon);

			// Meridional velocity
			DataArray3D<double> dataV(nLev, nLat, nLon);

			NcVar * varV = ncdf_in.get_var("V");
			varV->set_cur(t, 0, 0, 0);
			varV->get(&(dataV[0][0][0]), 1, nLev, nLat, nLon);

			// Vertical velocity
			DataArray3D<double> dataW(nLev, nLat, nLon);

			NcVar * varW = ncdf_in.get_var("W");
			varW->set_cur(t, 0, 0, 0);
			varW->get(&(dataW[0][0][0]), 1, nLev, nLat, nLon);

			// Calculate total energy
			double dTotalEnergy = 0.0;

			double dElementRefArea =
				dEarthRadius * dEarthRadius
				* M_PI / static_cast<double>(nLat)
				* 2.0 * M_PI / static_cast<double>(nLon);

			for (int k = 0; k < nLev; k++) {
			for (int i = 0; i < nLat; i++) {
			for (int j = 0; j < nLon; j++) {
				double dKineticEnergy =
					0.5 * dataRho[k][i][j] *
						( dataU[k][i][j] * dataU[k][i][j]
						+ dataV[k][i][j] * dataV[k][i][j]
						+ dataW[k][i][j] * dataW[k][i][j]);

				double dInternalEnergy =
					dataP[k][i][j] / (dGamma - 1.0);

				dTotalEnergy +=
					(dKineticEnergy + dInternalEnergy)
						* std::cos(M_PI * dLat[i] / 180.0) * dElementRefArea
						* (dZtop - dZs[i][j]) / static_cast<double>(nLev);
			}
			}
			}

			// Put total energy into file
			varEnergy->set_cur(t);
			varEnergy->put(&dTotalEnergy, 1);
		}

		AnnounceEndBlock("Done");
	}

	AnnounceEndBlock("Done");

} catch(Exception & e) {
	Announce(e.ToString().c_str());
}

	// Finalize MPI
	MPI_Finalize();
}
int main(int argc, char** argv) {

	NcError error(NcError::silent_nonfatal);

try {

	// Input / Output types
	enum DiscretizationType {
		DiscretizationType_FV,
		DiscretizationType_CGLL,
		DiscretizationType_DGLL
	};

	// Input mesh file
	std::string strInputMesh;

	// Overlap mesh file
	std::string strOverlapMesh;

	// Input metadata file
	std::string strInputMeta;

	// Output metadata file
	std::string strOutputMeta;

	// Input data type
	std::string strInputType;

	// Output data type
	std::string strOutputType;

	// Order of polynomial in each element
	int nPin;

	// Order of polynomial in each output element
	int nPout;

	// Use bubble on interior of spectral element nodes
	bool fBubble;

	// Enforce monotonicity
	bool fMonotoneType1;

	// Enforce monotonicity
	bool fMonotoneType2;

	// Enforce monotonicity
	bool fMonotoneType3;

	// Volumetric remapping
	bool fVolumetric;

	// No conservation
	bool fNoConservation;

	// Turn off checking for conservation / consistency
	bool fNoCheck;

	// Output mesh file
	std::string strOutputMesh;

	// Variable list
	std::string strVariables;

	// Output map file
	std::string strOutputMap;

	// Input data file
	std::string strInputData;

	// Output data file
	std::string strOutputData;

	// Name of the ncol variable
	std::string strNColName;

	// Output as double
	bool fOutputDouble;

	// List of variables to preserve
	std::string strPreserveVariables;

	// Preserve all non-remapped variables
	bool fPreserveAll;

	// Fill value override
	double dFillValueOverride;

	// Parse the command line
	BeginCommandLine()
		//CommandLineStringD(strMethod, "method", "", "[se]");
		CommandLineString(strInputMesh, "in_mesh", "");
		CommandLineString(strOutputMesh, "out_mesh", "");
		CommandLineString(strOverlapMesh, "ov_mesh", "");
		CommandLineString(strInputMeta, "in_meta", "");
		CommandLineString(strOutputMeta, "out_meta", "");
		CommandLineStringD(strInputType, "in_type", "fv", "[fv|cgll|dgll]");
		CommandLineStringD(strOutputType, "out_type", "fv", "[fv|cgll|dgll]");
		CommandLineInt(nPin, "in_np", 4);
		CommandLineInt(nPout, "out_np", 4);
		CommandLineBool(fBubble, "bubble");
		CommandLineBool(fMonotoneType1, "mono");
		CommandLineBool(fMonotoneType2, "mono2");
		CommandLineBool(fMonotoneType3, "mono3");
		CommandLineBool(fVolumetric, "volumetric");
		CommandLineBool(fNoConservation, "noconserve");
		CommandLineBool(fNoCheck, "nocheck");
		CommandLineString(strVariables, "var", "");
		CommandLineString(strOutputMap, "out_map", "");
		CommandLineString(strInputData, "in_data", "");
		CommandLineString(strOutputData, "out_data", "");
		CommandLineString(strNColName, "ncol_name", "ncol");
		CommandLineBool(fOutputDouble, "out_double");
		CommandLineString(strPreserveVariables, "preserve", "");
		CommandLineBool(fPreserveAll, "preserveall");
		CommandLineDouble(dFillValueOverride, "fillvalue", 0.0);

		ParseCommandLine(argc, argv);
	EndCommandLine(argv)

	AnnounceBanner();

	// Check command line parameters (mesh arguments)
	if (strInputMesh == "") {
		_EXCEPTIONT("No input mesh (--in_mesh) specified");
	}
	if (strOutputMesh == "") {
		_EXCEPTIONT("No output mesh (--out_mesh) specified");
	}

	// Overlap mesh
	if (strOverlapMesh == "") {
		_EXCEPTIONT("No overlap mesh specified");
	}

	// Check command line parameters (data arguments)
	if ((strInputData != "") && (strOutputData == "")) {
		_EXCEPTIONT("--in_data specified without --out_data");
	}
	if ((strInputData == "") && (strOutputData != "")) {
		_EXCEPTIONT("--out_data specified without --in_data");
	}

	// Check metadata parameters
	if ((strInputMeta != "") && (strInputType == "fv")) {
		_EXCEPTIONT("--in_meta cannot be used with --in_type fv");
	}
	if ((strOutputMeta != "") && (strOutputType == "fv")) {
		_EXCEPTIONT("--out_meta cannot be used with --out_type fv");
	}

	// Check command line parameters (data type arguments)
	STLStringHelper::ToLower(strInputType);
	STLStringHelper::ToLower(strOutputType);

	DiscretizationType eInputType;
	DiscretizationType eOutputType;

	if (strInputType == "fv") {
		eInputType = DiscretizationType_FV;
	} else if (strInputType == "cgll") {
		eInputType = DiscretizationType_CGLL;
	} else if (strInputType == "dgll") {
		eInputType = DiscretizationType_DGLL;
	} else {
		_EXCEPTION1("Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]",
			strInputType.c_str());
	}

	if (strOutputType == "fv") {
		eOutputType = DiscretizationType_FV;
	} else if (strOutputType == "cgll") {
		eOutputType = DiscretizationType_CGLL;
	} else if (strOutputType == "dgll") {
		eOutputType = DiscretizationType_DGLL;
	} else {
		_EXCEPTION1("Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]",
			strOutputType.c_str());
	}

	// Monotonicity flags
	int nMonotoneType = 0;
	if (fMonotoneType1) {
		nMonotoneType = 1;
	}
	if (fMonotoneType2) {
		if (nMonotoneType != 0) {
			_EXCEPTIONT("Only one of --mono, --mono2 and --mono3 may be set");
		}
		nMonotoneType = 2;
	}
	if (fMonotoneType3) {
		if (nMonotoneType != 0) {
			_EXCEPTIONT("Only one of --mono, --mono2 and --mono3 may be set");
		}
		nMonotoneType = 3;
	}
/*
	// Volumetric
	if (fVolumetric && (nMonotoneType != 0)) {
		_EXCEPTIONT("--volumetric cannot be used in conjunction with --mono#");
	}
*/
	// Create Offline Map
	OfflineMap mapRemap;

	// Initialize dimension information from file
	AnnounceStartBlock("Initializing dimensions of map");
	Announce("Input mesh");
	mapRemap.InitializeSourceDimensionsFromFile(strInputMesh);
	Announce("Output mesh");
	mapRemap.InitializeTargetDimensionsFromFile(strOutputMesh);
	AnnounceEndBlock(NULL);

	// Parse variable list
	std::vector< std::string > vecVariableStrings;
	ParseVariableList(strVariables, vecVariableStrings);

	// Parse preserve variable list
	std::vector< std::string > vecPreserveVariableStrings;
	ParseVariableList(strPreserveVariables, vecPreserveVariableStrings);

	if (fPreserveAll && (vecPreserveVariableStrings.size() != 0)) {
		_EXCEPTIONT("--preserveall and --preserve cannot both be specified");
	}

	// Load input mesh
	AnnounceStartBlock("Loading input mesh");
	Mesh meshInput(strInputMesh);
	meshInput.RemoveZeroEdges();
	AnnounceEndBlock(NULL);

	// Calculate Face areas
	AnnounceStartBlock("Calculating input mesh Face areas");
	double dTotalAreaInput = meshInput.CalculateFaceAreas();
	Announce("Input Mesh Geometric Area: %1.15e", dTotalAreaInput);
	AnnounceEndBlock(NULL);

	// Input mesh areas
	if (eInputType == DiscretizationType_FV) {
		mapRemap.SetSourceAreas(meshInput.vecFaceArea);
	}

	// Load output mesh
	AnnounceStartBlock("Loading output mesh");
	Mesh meshOutput(strOutputMesh);
	meshOutput.RemoveZeroEdges();
	AnnounceEndBlock(NULL);

	// Calculate Face areas
	AnnounceStartBlock("Calculating output mesh Face areas");
	Real dTotalAreaOutput = meshOutput.CalculateFaceAreas();
	Announce("Output Mesh Geometric Area: %1.15e", dTotalAreaOutput);
	AnnounceEndBlock(NULL);

	// Output mesh areas
	if (eOutputType == DiscretizationType_FV) {
		mapRemap.SetTargetAreas(meshOutput.vecFaceArea);
	}

	// Load overlap mesh
	AnnounceStartBlock("Loading overlap mesh");
	Mesh meshOverlap(strOverlapMesh);
	meshOverlap.RemoveZeroEdges();

	// Verify that overlap mesh is in the correct order
	int ixSourceFaceMax = (-1);
	int ixTargetFaceMax = (-1);

	if (meshOverlap.vecSourceFaceIx.size() !=
		meshOverlap.vecTargetFaceIx.size()
	) {
		_EXCEPTIONT("Invalid overlap mesh:\n"
			"    Possible mesh file corruption?");
	}

	for (int i = 0; i < meshOverlap.vecSourceFaceIx.size(); i++) {
		if (meshOverlap.vecSourceFaceIx[i] + 1 > ixSourceFaceMax) {
			ixSourceFaceMax = meshOverlap.vecSourceFaceIx[i] + 1;
		}
		if (meshOverlap.vecTargetFaceIx[i] + 1 > ixTargetFaceMax) {
			ixTargetFaceMax = meshOverlap.vecTargetFaceIx[i] + 1;
		}
	}

	// Check for forward correspondence in overlap mesh
	if (ixSourceFaceMax == meshInput.faces.size() //&&
		//(ixTargetFaceMax == meshOutput.faces.size())
	) {
		Announce("Overlap mesh forward correspondence found");

	// Check for reverse correspondence in overlap mesh
	} else if (
		ixSourceFaceMax == meshOutput.faces.size() //&&
		//(ixTargetFaceMax == meshInput.faces.size())
	) {
		Announce("Overlap mesh reverse correspondence found (reversing)");

		// Reorder overlap mesh
		meshOverlap.ExchangeFirstAndSecondMesh();

	// No correspondence found
	} else {
		_EXCEPTION2("Invalid overlap mesh:\n"
			"    No correspondence found with input and output meshes (%i,%i)",
			ixSourceFaceMax, ixTargetFaceMax);
	}

	AnnounceEndBlock(NULL);

	// Calculate Face areas
	AnnounceStartBlock("Calculating overlap mesh Face areas");
	Real dTotalAreaOverlap = meshOverlap.CalculateFaceAreas();
	Announce("Overlap Mesh Area: %1.15e", dTotalAreaOverlap);
	AnnounceEndBlock(NULL);

	// Partial cover
	if (fabs(dTotalAreaOverlap - dTotalAreaInput) > 1.0e-10) {
		if (!fNoCheck) {
			Announce("WARNING: Significant mismatch between overlap mesh area "
				"and input mesh area.\n  Automatically enabling --nocheck");
			fNoCheck = true;
		}
	}

/*
	// Recalculate input mesh area from overlap mesh
	if (fabs(dTotalAreaOverlap - dTotalAreaInput) > 1.0e-10) {
		AnnounceStartBlock("Overlap mesh only covers a sub-area of the sphere");
		Announce("Recalculating source mesh areas");
		dTotalAreaInput = meshInput.CalculateFaceAreasFromOverlap(meshOverlap);
		Announce("New Input Mesh Geometric Area: %1.15e", dTotalAreaInput);
		AnnounceEndBlock(NULL);
	}
*/
	// Finite volume input / Finite volume output
	if ((eInputType  == DiscretizationType_FV) &&
		(eOutputType == DiscretizationType_FV)
	) {

		// Generate reverse node array and edge map
		meshInput.ConstructReverseNodeArray();
		meshInput.ConstructEdgeMap();

		// Initialize coordinates for map
		mapRemap.InitializeSourceCoordinatesFromMeshFV(meshInput);
		mapRemap.InitializeTargetCoordinatesFromMeshFV(meshOutput);

		// Construct OfflineMap
		AnnounceStartBlock("Calculating offline map");
		LinearRemapFVtoFV(
			meshInput, meshOutput, meshOverlap, nPin, mapRemap);

	// Finite volume input / Finite element output
	} else if (eInputType == DiscretizationType_FV) {
		DataMatrix3D<int> dataGLLNodes;
		DataMatrix3D<double> dataGLLJacobian;

		if (strOutputMeta != "") {
			AnnounceStartBlock("Loading meta data file");
			LoadMetaDataFile(strOutputMeta, dataGLLNodes, dataGLLJacobian);
			AnnounceEndBlock(NULL);

		} else {
			AnnounceStartBlock("Generating output mesh meta data");
			double dNumericalArea =
				GenerateMetaData(
					meshOutput,
					nPout,
					fBubble,
					dataGLLNodes,
					dataGLLJacobian);

			Announce("Output Mesh Numerical Area: %1.15e", dNumericalArea);
			AnnounceEndBlock(NULL);
		}

		// Initialize coordinates for map
		mapRemap.InitializeSourceCoordinatesFromMeshFV(meshInput);
		mapRemap.InitializeTargetCoordinatesFromMeshFE(
			meshOutput, nPout, dataGLLNodes);

		// Generate the continuous Jacobian
		bool fContinuous = (eOutputType == DiscretizationType_CGLL);

		if (eOutputType == DiscretizationType_CGLL) {
			GenerateUniqueJacobian(
				dataGLLNodes,
				dataGLLJacobian,
				mapRemap.GetTargetAreas());

		} else {
			GenerateDiscontinuousJacobian(
				dataGLLJacobian,
				mapRemap.GetTargetAreas());
		}

		// Generate reverse node array and edge map
		meshInput.ConstructReverseNodeArray();
		meshInput.ConstructEdgeMap();

		// Generate remap weights
		AnnounceStartBlock("Calculating offline map");

		if (fVolumetric) {
			LinearRemapFVtoGLL_Volumetric(
				meshInput,
				meshOutput,
				meshOverlap,
				dataGLLNodes,
				dataGLLJacobian,
				mapRemap.GetTargetAreas(),
				nPin,
				mapRemap,
				nMonotoneType,
				fContinuous,
				fNoConservation);

		} else {
			LinearRemapFVtoGLL(
				meshInput,
				meshOutput,
				meshOverlap,
				dataGLLNodes,
				dataGLLJacobian,
				mapRemap.GetTargetAreas(),
				nPin,
				mapRemap,
				nMonotoneType,
				fContinuous,
				fNoConservation);
		}

	// Finite element input / Finite volume output
	} else if (
		(eInputType != DiscretizationType_FV) &&
		(eOutputType == DiscretizationType_FV)
	) {
		DataMatrix3D<int> dataGLLNodes;
		DataMatrix3D<double> dataGLLJacobian;

		if (strInputMeta != "") {
			AnnounceStartBlock("Loading meta data file");
			LoadMetaDataFile(strInputMeta, dataGLLNodes, dataGLLJacobian);
			AnnounceEndBlock(NULL);

		} else {
			AnnounceStartBlock("Generating input mesh meta data");
			double dNumericalArea =
				GenerateMetaData(
					meshInput,
					nPin,
					fBubble,
					dataGLLNodes,
					dataGLLJacobian);

			Announce("Input Mesh Numerical Area: %1.15e", dNumericalArea);
			AnnounceEndBlock(NULL);

			if (fabs(dNumericalArea - dTotalAreaInput) > 1.0e-12) {
				Announce("WARNING: Significant mismatch between input mesh "
					"numerical area and geometric area");
			}
		}

		if (dataGLLNodes.GetSubColumns() != meshInput.faces.size()) {
			_EXCEPTIONT("Number of element does not match between metadata and "
				"input mesh");
		}

		// Initialize coordinates for map
		mapRemap.InitializeSourceCoordinatesFromMeshFE(
			meshInput, nPin, dataGLLNodes);
		mapRemap.InitializeTargetCoordinatesFromMeshFV(meshOutput);

		// Generate the continuous Jacobian for input mesh
		bool fContinuousIn = (eInputType == DiscretizationType_CGLL);

		if (eInputType == DiscretizationType_CGLL) {
			GenerateUniqueJacobian(
				dataGLLNodes,
				dataGLLJacobian,
				mapRemap.GetSourceAreas());

		} else {
			GenerateDiscontinuousJacobian(
				dataGLLJacobian,
				mapRemap.GetSourceAreas());
		}

		// Generate offline map
		AnnounceStartBlock("Calculating offline map");

		if (fVolumetric) {
			_EXCEPTIONT("Unimplemented: Volumetric currently unavailable for"
				"GLL input mesh");
		}

		LinearRemapSE4(
			meshInput,
			meshOutput,
			meshOverlap,
			dataGLLNodes,
			dataGLLJacobian,
			nMonotoneType,
			fContinuousIn,
			fNoConservation,
			mapRemap
		);

	// Finite element input / Finite element output
	} else if (
		(eInputType  != DiscretizationType_FV) &&
		(eOutputType != DiscretizationType_FV)
	) {
		DataMatrix3D<int> dataGLLNodesIn;
		DataMatrix3D<double> dataGLLJacobianIn;

		DataMatrix3D<int> dataGLLNodesOut;
		DataMatrix3D<double> dataGLLJacobianOut;

		// Input metadata
		if (strInputMeta != "") {
			AnnounceStartBlock("Loading input meta data file");
			LoadMetaDataFile(
				strInputMeta, dataGLLNodesIn, dataGLLJacobianIn);
			AnnounceEndBlock(NULL);

		} else {
			AnnounceStartBlock("Generating input mesh meta data");
			double dNumericalAreaIn =
				GenerateMetaData(
					meshInput,
					nPin,
					fBubble,
					dataGLLNodesIn,
					dataGLLJacobianIn);

			Announce("Input Mesh Numerical Area: %1.15e", dNumericalAreaIn);
			AnnounceEndBlock(NULL);

			if (fabs(dNumericalAreaIn - dTotalAreaInput) > 1.0e-12) {
				Announce("WARNING: Significant mismatch between input mesh "
					"numerical area and geometric area");
			}
		}

		// Output metadata
		if (strOutputMeta != "") {
			AnnounceStartBlock("Loading output meta data file");
			LoadMetaDataFile(
				strOutputMeta, dataGLLNodesOut, dataGLLJacobianOut);
			AnnounceEndBlock(NULL);

		} else {
			AnnounceStartBlock("Generating output mesh meta data");
			double dNumericalAreaOut =
				GenerateMetaData(
					meshOutput,
					nPout,
					fBubble,
					dataGLLNodesOut,
					dataGLLJacobianOut);

			Announce("Output Mesh Numerical Area: %1.15e", dNumericalAreaOut);
			AnnounceEndBlock(NULL);

			if (fabs(dNumericalAreaOut - dTotalAreaOutput) > 1.0e-12) {
				Announce("WARNING: Significant mismatch between output mesh "
					"numerical area and geometric area");
			}
		}

		// Initialize coordinates for map
		mapRemap.InitializeSourceCoordinatesFromMeshFE(
			meshInput, nPin, dataGLLNodesIn);
		mapRemap.InitializeTargetCoordinatesFromMeshFE(
			meshOutput, nPout, dataGLLNodesOut);

		// Generate the continuous Jacobian for input mesh
		bool fContinuousIn = (eInputType == DiscretizationType_CGLL);

		if (eInputType == DiscretizationType_CGLL) {
			GenerateUniqueJacobian(
				dataGLLNodesIn,
				dataGLLJacobianIn,
				mapRemap.GetSourceAreas());

		} else {
			GenerateDiscontinuousJacobian(
				dataGLLJacobianIn,
				mapRemap.GetSourceAreas());
		}

		// Generate the continuous Jacobian for output mesh
		bool fContinuousOut = (eOutputType == DiscretizationType_CGLL);

		if (eOutputType == DiscretizationType_CGLL) {
			GenerateUniqueJacobian(
				dataGLLNodesOut,
				dataGLLJacobianOut,
				mapRemap.GetTargetAreas());

		} else {
			GenerateDiscontinuousJacobian(
				dataGLLJacobianOut,
				mapRemap.GetTargetAreas());
		}

		// Generate offline map
		AnnounceStartBlock("Calculating offline map");

		LinearRemapGLLtoGLL2(
			meshInput,
			meshOutput,
			meshOverlap,
			dataGLLNodesIn,
			dataGLLJacobianIn,
			dataGLLNodesOut,
			dataGLLJacobianOut,
			mapRemap.GetTargetAreas(),
			nPin,
			nPout,
			nMonotoneType,
			fContinuousIn,
			fContinuousOut,
			fNoConservation,
			mapRemap
		);

	} else {
		_EXCEPTIONT("Not implemented");
	}

//#pragma warning "NOTE: VERIFICATION DISABLED"

	// Verify consistency, conservation and monotonicity
	if (!fNoCheck) {
		AnnounceStartBlock("Verifying map");
		mapRemap.IsConsistent(1.0e-8);
		mapRemap.IsConservative(1.0e-8);

		if (nMonotoneType != 0) {
			mapRemap.IsMonotone(1.0e-12);
		}
		AnnounceEndBlock(NULL);
	}

	AnnounceEndBlock(NULL);

	// Initialize element dimensions from input/output Mesh
	AnnounceStartBlock("Writing output");

	// Output the Offline Map
	if (strOutputMap != "") {
		AnnounceStartBlock("Writing offline map");
		mapRemap.Write(strOutputMap);
		AnnounceEndBlock(NULL);
	}

	// Apply Offline Map to data
	if (strInputData != "") {
		AnnounceStartBlock("Applying offline map to data");

		mapRemap.SetFillValueOverride(static_cast<float>(dFillValueOverride));
		mapRemap.Apply(
			strInputData,
			strOutputData,
			vecVariableStrings,
			strNColName,
			fOutputDouble,
			false);
		AnnounceEndBlock(NULL);
	}
	AnnounceEndBlock(NULL);

	// Copy variables from input file to output file
	if ((strInputData != "") && (strOutputData != "")) {
		if (fPreserveAll) {
			AnnounceStartBlock("Preserving variables");
			mapRemap.PreserveAllVariables(strInputData, strOutputData);
			AnnounceEndBlock(NULL);

		} else if (vecPreserveVariableStrings.size() != 0) {
			AnnounceStartBlock("Preserving variables");
			mapRemap.PreserveVariables(
				strInputData,
				strOutputData,
				vecPreserveVariableStrings);
			AnnounceEndBlock(NULL);
		}
	}

	AnnounceBanner();

	return (0);

} catch(Exception & e) {
	Announce(e.ToString().c_str());
	return (-1);

} catch(...) {
	return (-2);
}
}
Example #13
0
int main(int argc, char** argv) {

	NcError error(NcError::silent_nonfatal);

try {
	// Input filename
	std::string strInputFile;

	// Output mesh filename
	std::string strOutputFile;

	// Parse the command line
	BeginCommandLine()
		CommandLineString(strInputFile, "in", "");
		CommandLineString(strOutputFile, "out", "");

		ParseCommandLine(argc, argv);
	EndCommandLine(argv)

	// Check file names
	if (strInputFile == "") {
		std::cout << "ERROR: No input file specified" << std::endl;
		return (-1);
	}
	if (strOutputFile == "") {
		std::cout << "ERROR: No output file specified" << std::endl;
		return (-1);
	}

	AnnounceBanner();

	// Load shapefile
	AnnounceStartBlock("Loading shapefile");

	std::ifstream shpfile(
		strInputFile.c_str(), std::ios::in | std::ios::binary);

	SHPHeader shphead;
	shpfile.read((char*)(&shphead), sizeof(SHPHeader));

	if (O32_HOST_ORDER == O32_LITTLE_ENDIAN) {
		shphead.iFileCode = SwapEndianInt32(shphead.iFileCode);
		shphead.iFileLength = SwapEndianInt32(shphead.iFileLength);
	} else if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
		shphead.iVersion = SwapEndianInt32(shphead.iVersion);
		shphead.iShapeType = SwapEndianInt32(shphead.iShapeType);
	} else {
		_EXCEPTIONT("Invalid system Endian");
	}

	if (shphead.iFileCode != SHPFileCodeRef) {
		_EXCEPTIONT("Input file does not appear to be a ESRI Shapefile: "
			"File code mismatch");
	}
	if (shphead.iVersion != SHPVersionRef) {
		_EXCEPTIONT("Input file error: Version mismatch");
	}
	if (shphead.iShapeType != SHPPolygonType) {
		_EXCEPTIONT("Input file error: Polygon type expected");
	}

	SHPBounds shpbounds;
	shpfile.read((char*)(&shpbounds), sizeof(SHPBounds));

	if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
		shpbounds.dXmin = SwapEndianDouble(shpbounds.dXmin);
		shpbounds.dYmin = SwapEndianDouble(shpbounds.dYmin);
		shpbounds.dXmax = SwapEndianDouble(shpbounds.dXmax);
		shpbounds.dYmax = SwapEndianDouble(shpbounds.dXmax);

		shpbounds.dZmin = SwapEndianDouble(shpbounds.dZmin);
		shpbounds.dZmax = SwapEndianDouble(shpbounds.dZmax);

		shpbounds.dMmin = SwapEndianDouble(shpbounds.dMmin);
		shpbounds.dMmax = SwapEndianDouble(shpbounds.dMmax);
	}

	// Current position (in 16-bit words)
	int32_t iCurrentPosition = 50;

	int32_t iPolygonIx = 1;

	// Exodus mesh
	Mesh mesh;

	// Load records
	while (iCurrentPosition < shphead.iFileLength) {

		// Read the record header
		SHPRecordHeader shprechead;
		shpfile.read((char*)(&shprechead), sizeof(SHPRecordHeader));
		if (shpfile.eof()) {
			break;
		}

		if (O32_HOST_ORDER == O32_LITTLE_ENDIAN) {
			shprechead.iNumber = SwapEndianInt32(shprechead.iNumber);
			shprechead.nLength = SwapEndianInt32(shprechead.nLength);
		}

		char szBuffer[128];
		sprintf(szBuffer, "Polygon %i", shprechead.iNumber);
		iPolygonIx++;
		AnnounceStartBlock(szBuffer);

		iCurrentPosition += shprechead.nLength;

		// Read the shape type
		int32_t iShapeType;
		shpfile.read((char*)(&iShapeType), sizeof(int32_t));
		if (shpfile.eof()) {
			break;
		}

		if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
			iShapeType = SwapEndianInt32(iShapeType);
		}
		if (iShapeType != SHPPolygonType) {
			_EXCEPTIONT("Input file error: Record Polygon type expected");
		}

		// Read the polygon header
		SHPPolygonHeader shppolyhead;
		shpfile.read((char*)(&shppolyhead), sizeof(SHPPolygonHeader));
		if (shpfile.eof()) {
			break;
		}

		if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
			shppolyhead.dXmin = SwapEndianDouble(shppolyhead.dXmin);
			shppolyhead.dYmin = SwapEndianDouble(shppolyhead.dYmin);
			shppolyhead.dXmax = SwapEndianDouble(shppolyhead.dXmax);
			shppolyhead.dYmax = SwapEndianDouble(shppolyhead.dYmax);
			shppolyhead.nNumParts = SwapEndianInt32(shppolyhead.nNumParts);
			shppolyhead.nNumPoints = SwapEndianInt32(shppolyhead.nNumPoints);
		}

		// Sanity check
		if (shppolyhead.nNumParts > 0x1000000) {
			_EXCEPTION1("Polygon NumParts exceeds sanity bound (%i)",
				shppolyhead.nNumParts);
		}
		if (shppolyhead.nNumPoints > 0x1000000) {
			_EXCEPTION1("Polygon NumPoints exceeds sanity bound (%i)",
				shppolyhead.nNumPoints);
		}
		Announce("containing %i part(s) with %i points",
			shppolyhead.nNumParts,
			shppolyhead.nNumPoints);
		Announce("Xmin: %3.5f", shppolyhead.dXmin);
		Announce("Ymin: %3.5f", shppolyhead.dYmin);
		Announce("Xmax: %3.5f", shppolyhead.dXmax);
		Announce("Ymax: %3.5f", shppolyhead.dYmax);

		if (shppolyhead.nNumParts != 1) {
			_EXCEPTIONT("Only polygons with 1 part currently supported"
				" in Exodus format");
		}

		DataVector<int32_t> iParts(shppolyhead.nNumParts);
		shpfile.read((char*)&(iParts[0]),
			shppolyhead.nNumParts * sizeof(int32_t));
		if (shpfile.eof()) {
			break;
		}

		DataVector<double> dPoints(shppolyhead.nNumPoints * 2);
		shpfile.read((char*)&(dPoints[0]),
			shppolyhead.nNumPoints * 2 * sizeof(double));
		if (shpfile.eof()) {
			break;
		}

		if (O32_HOST_ORDER == O32_BIG_ENDIAN) {
			for (int i = 0; i < shppolyhead.nNumParts; i++) {
				iParts[i] = SwapEndianInt32(iParts[i]);
			}
			for (int i = 0; i < shppolyhead.nNumPoints * 2; i++) {
				dPoints[i] = SwapEndianDouble(dPoints[i]);
			}
		}

		// Convert to Exodus mesh
		int nFaces = mesh.faces.size();
		int nNodes = mesh.nodes.size();
		mesh.faces.resize(nFaces+1);
		mesh.nodes.resize(nNodes + shppolyhead.nNumPoints);

		mesh.faces[nFaces] = Face(shppolyhead.nNumPoints);
		for (int i = 0; i < shppolyhead.nNumPoints; i++) {
			double dLonRad = dPoints[2*i] / 180.0 * M_PI;
			double dLatRad = dPoints[2*i+1] / 180.0 * M_PI;

			mesh.nodes[nNodes+i].x = cos(dLatRad) * cos(dLonRad);
			mesh.nodes[nNodes+i].y = cos(dLatRad) * sin(dLonRad);
			mesh.nodes[nNodes+i].z = sin(dLatRad);

			mesh.faces[nFaces].SetNode(i, nNodes + i);
		}

		AnnounceEndBlock("Done");
	}

	AnnounceEndBlock("Done");

	// Write to file
	AnnounceStartBlock("Write Exodus mesh");

	mesh.Write(strOutputFile);

	AnnounceEndBlock("Done");

	// Announce
	AnnounceBanner();

	return (0);

} catch(Exception & e) {
	Announce(e.ToString().c_str());
	return (-1);

} catch(...) {
	return (-2);
}
}
void GridPatchCartesianGLL::EvaluateGeometricTerms() {

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

	// Obtain Gauss Lobatto quadrature nodes and weights
	DataVector<double> dGL;
	DataVector<double> dWL;

	GaussLobattoQuadrature::GetPoints(m_nHorizontalOrder, 0.0, 1.0, dGL, dWL);

	// Obtain normalized areas in the vertical
	const DataVector<double> & dWNode =
		m_grid.GetREtaLevelsNormArea();
	const DataVector<double> & dWREdge =
		m_grid.GetREtaInterfacesNormArea();

	// Verify that normalized areas are correct
	double dWNodeSum = 0.0;
	for (int k = 0; k < dWNode.GetRows(); k++) {
		dWNodeSum += dWNode[k];
	}
	if (fabs(dWNodeSum - 1.0) > 1.0e-13) {
		_EXCEPTION1("Error in normalized areas (%1.15e)", dWNodeSum);
	}

	if (m_grid.GetVerticalStaggering() !=
	    Grid::VerticalStaggering_Interfaces
	) {
		double dWREdgeSum = 0.0;
		for (int k = 0; k < dWREdge.GetRows(); k++) {
			dWREdgeSum += dWREdge[k];
		}
		if (fabs(dWREdgeSum - 1.0) > 1.0e-13) {
			_EXCEPTION1("Error in normalized areas (%1.15e)", dWREdgeSum);
		}
	}

	// Derivatives of basis functions
	GridCartesianGLL & gridCartesianGLL =
		dynamic_cast<GridCartesianGLL &>(m_grid);

	const DataMatrix<double> & dDxBasis1D = gridCartesianGLL.GetDxBasis1D();
	
	double dy0 = 0.5 * fabs(m_dGDim[3] - m_dGDim[2]);
	double dfp = 2.0 * phys.GetOmega() * sin(m_dRefLat);
	double dbetap = 2.0 * phys.GetOmega() * cos(m_dRefLat) / 
					phys.GetEarthRadius();
	// Initialize the Coriolis force at each node
	for (int i = 0; i < m_box.GetATotalWidth(); i++) {
	for (int j = 0; j < m_box.GetBTotalWidth(); j++) {
		// Coriolis force by beta approximation
		//m_dataCoriolisF[i][j] = dfp + dbetap * (m_dataLat[i][j] - dy0);
		//m_dataCoriolisF[i][j] = dfp;
		//m_dataCoriolisF[i][j] = 0.0;
	}
	}

	// Initialize metric and Christoffel symbols in terrain-following coords
	for (int a = 0; a < GetElementCountA(); a++) {
	for (int b = 0; b < GetElementCountB(); b++) {

		for (int i = 0; i < m_nHorizontalOrder; i++) {
		for (int j = 0; j < m_nHorizontalOrder; j++) {

			// Nodal points
			int iElementA = m_box.GetAInteriorBegin() + a * m_nHorizontalOrder;
			int iElementB = m_box.GetBInteriorBegin() + b * m_nHorizontalOrder;

			int iA = iElementA + i;
			int iB = iElementB + j;

			// Topography height and its derivatives
			double dZs = m_dataTopography[iA][iB];
			double dDaZs = m_dataTopographyDeriv[0][iA][iB];
			double dDbZs = m_dataTopographyDeriv[1][iA][iB];

			// Initialize 2D Jacobian
			m_dataJacobian2D[iA][iB] = 1.0;

			// Initialize 2D contravariant metric
			m_dataContraMetric2DA[iA][iB][0] = 1.0;
			m_dataContraMetric2DA[iA][iB][1] = 0.0;

			m_dataContraMetric2DB[iA][iB][0] = 0.0;
			m_dataContraMetric2DB[iA][iB][1] = 1.0;

			// Initialize 2D covariant metric
			m_dataCovMetric2DA[iA][iB][0] = 1.0;
			m_dataCovMetric2DA[iA][iB][1] = 0.0;

			m_dataCovMetric2DB[iA][iB][0] = 0.0;
			m_dataCovMetric2DB[iA][iB][1] = 1.0;

			// Vertical coordinate transform and its derivatives
			for (int k = 0; k < m_grid.GetRElements(); k++) {

				// Gal-Chen and Somerville (1975) terrain following coord
				// Schar Exponential Decay terrain following coord
				double dREta = m_grid.GetREtaLevel(k);

				double dREtaStretch;
				double dDxREtaStretch;
				m_grid.EvaluateVerticalStretchF(
					dREta, dREtaStretch, dDxREtaStretch);

				//double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;
				//double dbZ = sinh(m_grid.GetZtop() * (1.0 - dREtaStretch) / m_dSL)
				//	/ sinh(m_grid.GetZtop() / m_dSL);
				//double dZ = m_grid.GetZtop() * dREtaStretch + dZs; // * dbZ;

				double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;

				double dDaZ = (1.0 - dREtaStretch) * dDaZs;
				double dDbZ = (1.0 - dREtaStretch) * dDbZs;
				double dDxZ = (m_grid.GetZtop() - dZs) * dDxREtaStretch;

/*
				double dDaZ = dbZ * dDaZs;
				double dDbZ = dbZ * dDbZs;
				double dDxZ = m_grid.GetZtop() - dZs * m_grid.GetZtop() * 
					cosh(m_grid.GetZtop() * (1.0 - dREtaStretch) / m_dSL) /
					(m_dSL * sinh(m_grid.GetZtop() / m_dSL));
				dDxZ *= dDxREtaStretch;
*/
				// Calculate pointwise Jacobian
				m_dataJacobian[k][iA][iB] =
					dDxZ * m_dataJacobian2D[iA][iB];

				// Element area associated with each model level GLL node
				m_dataElementArea[k][iA][iB] =
					m_dataJacobian[k][iA][iB]
					* dWL[i] * GetElementDeltaA()
					* dWL[j] * GetElementDeltaB()
					* dWNode[k];

				// Contravariant metric components
				m_dataContraMetricA[k][iA][iB][0] =
					m_dataContraMetric2DA[iA][iB][0];
				m_dataContraMetricA[k][iA][iB][1] =
					m_dataContraMetric2DA[iA][iB][1];
				m_dataContraMetricA[k][iA][iB][2] =
					- dDaZ / dDxZ;

				m_dataContraMetricB[k][iA][iB][0] =
					m_dataContraMetric2DB[iA][iB][0];
				m_dataContraMetricB[k][iA][iB][1] =
					m_dataContraMetric2DB[iA][iB][1];
				m_dataContraMetricB[k][iA][iB][2] =
					- dDbZ / dDxZ;

				m_dataContraMetricXi[k][iA][iB][0] =
					m_dataContraMetricA[k][iA][iB][2];
				m_dataContraMetricXi[k][iA][iB][1] =
					m_dataContraMetricB[k][iA][iB][2];
				m_dataContraMetricXi[k][iA][iB][2] =
					(1.0 + dDaZ * dDaZ + dDbZ * dDbZ) / (dDxZ * dDxZ);

				// Covariant metric components
				m_dataCovMetricA[k][iA][iB][0] =
					m_dataCovMetric2DA[iA][iB][0] + dDaZ * dDaZ;
				m_dataCovMetricA[k][iA][iB][1] =
					m_dataCovMetric2DA[iA][iB][1] + dDaZ * dDbZ;
				m_dataCovMetricA[k][iA][iB][2] =
					dDaZ * dDxZ;

				m_dataCovMetricB[k][iA][iB][0] =
					m_dataCovMetric2DB[iA][iB][0] + dDbZ * dDaZ;
				m_dataCovMetricB[k][iA][iB][1] =
					m_dataCovMetric2DB[iA][iB][1] + dDbZ * dDbZ;
				m_dataCovMetricB[k][iA][iB][2] =
					dDbZ * dDxZ;

				m_dataCovMetricXi[k][iA][iB][0] =
					dDaZ * dDxZ;
				m_dataCovMetricXi[k][iA][iB][1] =
					dDbZ * dDxZ;
				m_dataCovMetricXi[k][iA][iB][2] =
					dDxZ * dDxZ;

				// Derivatives of the vertical coordinate transform
				m_dataDerivRNode[k][iA][iB][0] = dDaZ;
				m_dataDerivRNode[k][iA][iB][1] = dDbZ;
				m_dataDerivRNode[k][iA][iB][2] = dDxZ;
			}

			// Metric terms at vertical interfaces
			for (int k = 0; k <= m_grid.GetRElements(); k++) {

				// Gal-Chen and Somerville (1975) terrain following coord
				// Schar Exponential decay terrain following coord
				double dREta = m_grid.GetREtaInterface(k);
/*				
				double dREtaStretch;
				double dDxREtaStretch;
				m_grid.EvaluateVerticalStretchF(
					dREta, dREtaStretch, dDxREtaStretch);

				double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;

				double dDaZ = (1.0 - dREtaStretch) * dDaZs;
				double dDbZ = (1.0 - dREtaStretch) * dDbZs;
				double dDxZ = (m_grid.GetZtop() - dZs) * dDxREtaStretch;
*/
				double dREtaStretch;
				double dDxREtaStretch;
				m_grid.EvaluateVerticalStretchF(
					dREta, dREtaStretch, dDxREtaStretch);
/*
				//double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;
				double dbZ = sinh(m_grid.GetZtop() * (1.0 - dREtaStretch) / m_dSL) / 
					sinh(m_grid.GetZtop() / m_dSL);
				double dZ = m_grid.GetZtop() * dREtaStretch + dZs * dbZ;
*/

				double dDaZ = (1.0 - dREtaStretch) * dDaZs;
				double dDbZ = (1.0 - dREtaStretch) * dDbZs;
		     	double dDxZ = (m_grid.GetZtop() - dZs) * dDxREtaStretch;
/*
				double dDaZ = dbZ * dDaZs;
				double dDbZ = dbZ * dDbZs;
				double dDxZ = m_grid.GetZtop() - dZs * m_grid.GetZtop() * 
					cosh(m_grid.GetZtop() * (1.0 - dREtaStretch) / m_dSL) /
					(m_dSL * sinh(m_grid.GetZtop() / m_dSL));
				dDxZ *= dDxREtaStretch;
*/
				// Calculate pointwise Jacobian
				m_dataJacobianREdge[k][iA][iB] =
					dDxZ * m_dataJacobian2D[iA][iB];

				// Element area associated with each model interface GLL node
				m_dataElementAreaREdge[k][iA][iB] =
					m_dataJacobianREdge[k][iA][iB]
					* dWL[i] * GetElementDeltaA()
					* dWL[j] * GetElementDeltaB()
					* dWREdge[k];

				// Components of the contravariant metric
				m_dataContraMetricAREdge[k][iA][iB][0] =
					m_dataContraMetric2DA[iA][iB][0];
				m_dataContraMetricAREdge[k][iA][iB][1] =
					m_dataContraMetric2DA[iA][iB][1];
				m_dataContraMetricAREdge[k][iA][iB][2] =
					- dDaZ / dDxZ;

				m_dataContraMetricBREdge[k][iA][iB][0] =
					m_dataContraMetric2DB[iA][iB][0];
				m_dataContraMetricBREdge[k][iA][iB][1] =
					m_dataContraMetric2DB[iA][iB][1];
				m_dataContraMetricBREdge[k][iA][iB][2] =
					- dDbZ / dDxZ;

				m_dataContraMetricXiREdge[k][iA][iB][0] =
					- dDaZ / dDxZ;
				m_dataContraMetricXiREdge[k][iA][iB][1] =
					- dDbZ / dDxZ;
				m_dataContraMetricXiREdge[k][iA][iB][2] =
					(1.0 + dDaZ * dDaZ + dDbZ * dDbZ) / (dDxZ * dDxZ);

				// Derivatives of the vertical coordinate transform
				m_dataDerivRREdge[k][iA][iB][0] = dDaZ;
				m_dataDerivRREdge[k][iA][iB][1] = dDbZ;
				m_dataDerivRREdge[k][iA][iB][2] = dDxZ;
			}
		}
		}
	}
	}
}
void ReadCFTimeDataFromNcFile(
	NcFile * ncfile,
	const std::string & strFilename,
	std::vector<Time> & vecTimes,
	bool fWarnOnMissingCalendar
) {
	// Empty existing Time vector
	vecTimes.clear();

	// Get time dimension
	NcDim * dimTime = ncfile->get_dim("time");
	if (dimTime == NULL) {
		_EXCEPTION1("Dimension \"time\" not found in file \"%s\"",
			strFilename.c_str());
	}

	// Get time variable
	NcVar * varTime = ncfile->get_var("time");
	if (varTime == NULL) {
		_EXCEPTION1("Variable \"time\" not found in file \"%s\"",
			strFilename.c_str());
	}
	if (varTime->num_dims() != 1) {
		_EXCEPTION1("Variable \"time\" has more than one dimension in file \"%s\"",
			strFilename.c_str());
	}
	if (strcmp(varTime->get_dim(0)->name(), "time") != 0) {
		_EXCEPTION1("Variable \"time\" does not have dimension \"time\" in file \"%s\"",
			strFilename.c_str());
	}

	// Calendar attribute
	NcAtt * attTimeCal = varTime->get_att("calendar");
	std::string strCalendar;
	if (attTimeCal == NULL) {
		if (fWarnOnMissingCalendar) {
			Announce("WARNING: Variable \"time\" is missing \"calendar\" attribute; assuming \"standard\"");
		}
		strCalendar = "standard";
	} else {
		strCalendar = attTimeCal->as_string(0);
	}
	Time::CalendarType eCalendarType =
		Time::CalendarTypeFromString(strCalendar);

	// Units attribute
	NcAtt * attTimeUnits = varTime->get_att("units");
	if (attTimeUnits == NULL) {
		_EXCEPTION1("Variable \"time\" is missing \"units\" attribute in file \"%s\"",
			strFilename.c_str());
	}
	std::string strTimeUnits = attTimeUnits->as_string(0);

	// Load in time data
	DataVector<int> vecTimeInt;
	DataVector<float> vecTimeFloat;
	DataVector<double> vecTimeDouble;
	DataVector<ncint64> vecTimeInt64;

	if (varTime->type() == ncInt) {
		vecTimeInt.Initialize(dimTime->size());
		varTime->set_cur((long)0);
		varTime->get(&(vecTimeInt[0]), dimTime->size());

	} else if (varTime->type() == ncFloat) {
		vecTimeFloat.Initialize(dimTime->size());
		varTime->set_cur((long)0);
		varTime->get(&(vecTimeFloat[0]), dimTime->size());

	} else if (varTime->type() == ncDouble) {
		vecTimeDouble.Initialize(dimTime->size());
		varTime->set_cur((long)0);
		varTime->get(&(vecTimeDouble[0]), dimTime->size());

	} else if (varTime->type() == ncInt64) {
		vecTimeInt64.Initialize(dimTime->size());
		varTime->set_cur((long)0);
		varTime->get(&(vecTimeInt64[0]), dimTime->size());

	} else {
		_EXCEPTION1("Variable \"time\" has invalid type "
			"(expected \"int\", \"int64\", \"float\" or \"double\")"
			" in file \"%s\"", strFilename.c_str());
	}

	for (int t = 0; t < dimTime->size(); t++) {
		Time time(eCalendarType);
		if (varTime->type() == ncInt) {
			time.FromCFCompliantUnitsOffsetInt(
				strTimeUnits,
				vecTimeInt[t]);

		} else if (varTime->type() == ncFloat) {
			time.FromCFCompliantUnitsOffsetDouble(
				strTimeUnits,
				static_cast<double>(vecTimeFloat[t]));

		} else if (varTime->type() == ncDouble) {
			time.FromCFCompliantUnitsOffsetDouble(
				strTimeUnits,
				vecTimeDouble[t]);

		} else if (varTime->type() == ncInt64) {
			time.FromCFCompliantUnitsOffsetInt(
				strTimeUnits,
				(int)(vecTimeInt64[t]));

		}

		vecTimes.push_back(time);
	}
}
Time OutputManagerComposite::Input(
    const std::string & strFileName
) {
#ifdef USE_MPI
    // Set the flag indicating that output came from a restart file
    m_fFromRestartFile = true;

    // Determine processor rank
    int nRank;
    MPI_Comm_rank(MPI_COMM_WORLD, &nRank);

    // The active model
    const Model & model = m_grid.GetModel();

    // Open binary input stream
    std::ifstream ifsActiveInput;
    ifsActiveInput.open(
        strFileName.c_str(), std::ios::binary | std::ios::in);

    if (!ifsActiveInput) {
        _EXCEPTION1("Unable to open input file \"%s\"",
                    strFileName.c_str());
    }

    // Read check bits
    int iCheckInput;
    ifsActiveInput.read((char *)(&iCheckInput), sizeof(int));
    if (iCheckInput != m_iCheck) {
        _EXCEPTION1("Invalid or incompatible input file \"%s\"",
                    strFileName.c_str());
    }

    // Read current time
    Time timeCurrent;
    ifsActiveInput.read((char *)(&(timeCurrent)), sizeof(Time));

    // Read Grid parameters from file
    DataContainer & dcGridParameters = m_grid.GetDataContainerParameters();
    int nGridParametersByteSize =
        dcGridParameters.GetTotalByteSize();
    char * pGridParameters =
        (char *)(dcGridParameters.GetPointer());

    ifsActiveInput.read(pGridParameters, nGridParametersByteSize);

    // Initialize the Grid from specified parameters
    m_grid.InitializeDataLocal();

    // Load Grid data from file
    DataContainer & dcGridPatchData = m_grid.GetDataContainerPatchData();
    int nGridPatchDataByteSize =
        dcGridPatchData.GetTotalByteSize();
    char * pGridPatchData =
        (char *)(dcGridPatchData.GetPointer());

    ifsActiveInput.read(pGridPatchData, nGridPatchDataByteSize);

    // Distribute GridPatches to processors
    m_grid.DistributePatches();

    // Determine space allocation for each GridPatch
    m_vecGridPatchByteSize.Allocate(m_grid.GetPatchCount(), 2);

    for (int i = 0; i < m_grid.GetActivePatchCount(); i++) {
        const GridPatch * pPatch = m_grid.GetActivePatch(i);

        int iPatchIx = pPatch->GetPatchIndex();
        if (iPatchIx > m_grid.GetPatchCount()) {
            _EXCEPTION2("PatchIndex (%i) out of range [0,%i)",
                        iPatchIx, m_grid.GetPatchCount());
        }

        const DataContainer & dcGeometric =
            pPatch->GetDataContainerGeometric();
        m_vecGridPatchByteSize[iPatchIx][0] =
            dcGeometric.GetTotalByteSize();

        const DataContainer & dcActiveState =
            pPatch->GetDataContainerActiveState();
        m_vecGridPatchByteSize[iPatchIx][1] =
            dcActiveState.GetTotalByteSize();
    }

    MPI_Allreduce(
        MPI_IN_PLACE,
        &(m_vecGridPatchByteSize[0][0]),
        m_vecGridPatchByteSize.GetTotalSize(),
        MPI_INT,
        MPI_MAX,
        MPI_COMM_WORLD);

    // Initialize byte location for each GridPatch
    m_vecGridPatchByteLoc.Allocate(m_grid.GetPatchCount(), 2);
    m_vecGridPatchByteLoc[0][0] = 0;
    m_vecGridPatchByteLoc[0][1] = m_vecGridPatchByteSize[0][0];
    for (int i = 1; i < m_vecGridPatchByteSize.GetRows(); i++) {
        m_vecGridPatchByteLoc[i][0] =
            m_vecGridPatchByteLoc[i-1][1]
            + m_vecGridPatchByteSize[i-1][1];

        m_vecGridPatchByteLoc[i][1] =
            m_vecGridPatchByteLoc[i][0]
            + m_vecGridPatchByteSize[i][0];
    }

    // Reference position
    std::streampos posRefFile = ifsActiveInput.tellg();
    if (posRefFile == (-1)) {
        _EXCEPTIONT("ActiveInput::tellg() fail");
    }

    // Load in GridPatch data from file
    for (int i = 0; i < m_grid.GetActivePatchCount(); i++) {
        GridPatch * pPatch = m_grid.GetActivePatch(i);

        int iPatchIx = pPatch->GetPatchIndex();
        if (iPatchIx > m_grid.GetPatchCount()) {
            _EXCEPTION2("PatchIndex (%i) out of range [0,%i)",
                        iPatchIx, m_grid.GetPatchCount());
        }

        DataContainer & dcGeometric =
            pPatch->GetDataContainerGeometric();
        int nGeometricDataByteSize =
            dcGeometric.GetTotalByteSize();
        char * pGeometricData =
            (char *)(dcGeometric.GetPointer());

        ifsActiveInput.seekg(
            posRefFile + m_vecGridPatchByteLoc[iPatchIx][0]);
        ifsActiveInput.read(
            pGeometricData, m_vecGridPatchByteSize[iPatchIx][0]);

        DataContainer & dcActiveState =
            pPatch->GetDataContainerActiveState();
        int nActiveStateDataByteSize =
            dcActiveState.GetTotalByteSize();
        char * pActiveStateData =
            (char *)(dcActiveState.GetPointer());

        ifsActiveInput.seekg(
            posRefFile + m_vecGridPatchByteLoc[iPatchIx][1]);
        ifsActiveInput.read(
            pActiveStateData, m_vecGridPatchByteSize[iPatchIx][1]);
    }

    // Close the file
    ifsActiveInput.close();

    // Barrier
    MPI_Barrier(MPI_COMM_WORLD);

#else
    _EXCEPTIONT("Not implemented without USE_MPI");
#endif

    return timeCurrent;
}
void OutputManagerComposite::Output(
    const Time & time
) {
#ifdef USE_MPI
    // Check for open file
    if (!IsFileOpen()) {
        _EXCEPTIONT("No file available for output");
    }

    // Verify that only one output has been performed
    if (m_ixOutputTime != 0) {
        _EXCEPTIONT("Only one Composite output allowed per file");
    }

    // Determine processor rank
    int nRank;
    MPI_Comm_rank(MPI_COMM_WORLD, &nRank);

    // Data types
    const int ExchangeDataType_Geometric = 0;
    const int ExchangeDataType_ActiveState = 1;
    const int ExchangeDataType_Count = 2;

    // Determine space allocation for each GridPatch
    m_vecGridPatchByteSize.Allocate(m_grid.GetPatchCount(), 2);

    for (int i = 0; i < m_grid.GetActivePatchCount(); i++) {
        const GridPatch * pPatch = m_grid.GetActivePatch(i);

        int iPatchIx = pPatch->GetPatchIndex();
        if (iPatchIx > m_grid.GetPatchCount()) {
            _EXCEPTION2("PatchIndex (%i) out of range [0,%i)",
                        iPatchIx, m_grid.GetPatchCount());
        }

        const DataContainer & dcGeometric =
            pPatch->GetDataContainerGeometric();
        m_vecGridPatchByteSize[iPatchIx][0] =
            dcGeometric.GetTotalByteSize();

        const DataContainer & dcActiveState =
            pPatch->GetDataContainerActiveState();
        m_vecGridPatchByteSize[iPatchIx][1] =
            dcActiveState.GetTotalByteSize();
    }

    // Reduce GridPatch byte size
    if (nRank != 0) {
        MPI_Reduce(
            &(m_vecGridPatchByteSize[0][0]),
            &(m_vecGridPatchByteSize[0][0]),
            m_vecGridPatchByteSize.GetTotalSize(),
            MPI_INT,
            MPI_MAX,
            0,
            MPI_COMM_WORLD);

        // Reduce GridPatch byte size and write Grid information
    } else if (nRank == 0) {

        // Reduce
        MPI_Reduce(
            MPI_IN_PLACE,
            &(m_vecGridPatchByteSize[0][0]),
            m_vecGridPatchByteSize.GetTotalSize(),
            MPI_INT,
            MPI_MAX,
            0,
            MPI_COMM_WORLD);

        // The active Model
        const Model & model = m_grid.GetModel();

        // Get maximum byte size for exchange
        int sMaxRecvBufferByteSize = 0;
        for (int i = 0; i < m_vecGridPatchByteSize.GetRows(); i++) {
            if (m_vecGridPatchByteSize[i][0] > sMaxRecvBufferByteSize) {
                sMaxRecvBufferByteSize = m_vecGridPatchByteSize[i][0];
            }
            if (m_vecGridPatchByteSize[i][1] > sMaxRecvBufferByteSize) {
                sMaxRecvBufferByteSize = m_vecGridPatchByteSize[i][1];
            }
        }

        // Allocate Recv buffer at root
        if (m_vecRecvBuffer.GetRows() < sMaxRecvBufferByteSize) {
            m_vecRecvBuffer.Allocate(sMaxRecvBufferByteSize);
        }

        // Initialize byte location for each GridPatch
        m_vecGridPatchByteLoc.Allocate(m_grid.GetPatchCount(), 2);
        m_vecGridPatchByteLoc[0][0] = 0;
        m_vecGridPatchByteLoc[0][1] = m_vecGridPatchByteSize[0][0];
        for (int i = 1; i < m_vecGridPatchByteSize.GetRows(); i++) {
            m_vecGridPatchByteLoc[i][0] =
                m_vecGridPatchByteLoc[i-1][1]
                + m_vecGridPatchByteSize[i-1][1];

            m_vecGridPatchByteLoc[i][1] =
                m_vecGridPatchByteLoc[i][0]
                + m_vecGridPatchByteSize[i][0];
        }

        // Write check bits
        m_ofsActiveOutput.write((const char *)(&m_iCheck), sizeof(int));

        // Write current time
        const Time & timeCurrent = model.GetCurrentTime();
        m_ofsActiveOutput.write((const char *)(&(timeCurrent)), sizeof(Time));

        // Write Grid information to file
        const DataContainer & dcGridParameters =
            m_grid.GetDataContainerParameters();
        int nGridParametersByteSize =
            dcGridParameters.GetTotalByteSize();
        const char * pGridParameters =
            (const char *)(dcGridParameters.GetPointer());

        m_ofsActiveOutput.write(
            pGridParameters, nGridParametersByteSize);

        const DataContainer & dcGridPatchData =
            m_grid.GetDataContainerPatchData();
        int nGridPatchDataByteSize =
            dcGridPatchData.GetTotalByteSize();
        const char * pGridPatchData =
            (const char *)(dcGridPatchData.GetPointer());

        m_ofsActiveOutput.write(
            pGridPatchData, nGridPatchDataByteSize);
    }

    // Send data from GridPatches to root
    if (nRank != 0) {

        int nActivePatches = m_grid.GetActivePatchCount();
        if (nActivePatches == 0) {
            _EXCEPTIONT("No GridPatches on processor");
        }

        DataArray1D<MPI_Request> vecSendReqGeo(nActivePatches);
        DataArray1D<MPI_Request> vecSendReqAcS(nActivePatches);

        for (int i = 0; i < nActivePatches; i++) {
            const GridPatch * pPatch = m_grid.GetActivePatch(i);

            const DataContainer & dcGeometric =
                pPatch->GetDataContainerGeometric();
            int nGeometricDataByteSize =
                dcGeometric.GetTotalByteSize();
            const unsigned char * pGeometricData =
                dcGeometric.GetPointer();

            MPI_Isend(
                const_cast<unsigned char *>(pGeometricData),
                nGeometricDataByteSize,
                MPI_BYTE,
                0,
                ExchangeDataType_Geometric,
                MPI_COMM_WORLD,
                &(vecSendReqGeo[i]));

            const DataContainer & dcActiveState =
                pPatch->GetDataContainerActiveState();
            int nActiveStateDataByteSize =
                dcActiveState.GetTotalByteSize();
            const unsigned char * pActiveStateData =
                dcActiveState.GetPointer();

            MPI_Isend(
                const_cast<unsigned char *>(pActiveStateData),
                nActiveStateDataByteSize,
                MPI_BYTE,
                0,
                ExchangeDataType_ActiveState,
                MPI_COMM_WORLD,
                &(vecSendReqAcS[i]));
            /*
            			printf("Send Geo %i %i\n", pPatch->GetPatchIndex(), nGeometricDataByteSize);
            			printf("Send AcS %i %i\n", pPatch->GetPatchIndex(), nActiveStateDataByteSize);
            */
        }

        int iWaitAllMsgGeo =
            MPI_Waitall(
                nActivePatches,
                &(vecSendReqGeo[0]),
                MPI_STATUSES_IGNORE);

        if (iWaitAllMsgGeo == MPI_ERR_IN_STATUS) {
            _EXCEPTIONT("MPI_Waitall returned MPI_ERR_IN_STATUS");
        }

        int iWaitAllMsgAcS =
            MPI_Waitall(
                nActivePatches,
                &(vecSendReqAcS[0]),
                MPI_STATUSES_IGNORE);

        if (iWaitAllMsgAcS == MPI_ERR_IN_STATUS) {
            _EXCEPTIONT("MPI_Waitall returned MPI_ERR_IN_STATUS");
        }

        //std::cout << "WAIT DONE" << std::endl;

        // Receive data and output to file
    } else {

        // Reference position
        std::streampos posRefFile = m_ofsActiveOutput.tellp();
        if (posRefFile == (-1)) {
            _EXCEPTIONT("ActiveOutput::tellp() fail");
        }

        // Write my GridPatch data to file
        for (int i = 0; i < m_grid.GetActivePatchCount(); i++) {
            const GridPatch * pPatch = m_grid.GetActivePatch(i);

            int iPatchIx = pPatch->GetPatchIndex();
            if (iPatchIx > m_grid.GetPatchCount()) {
                _EXCEPTION2("PatchIndex (%i) out of range [0,%i)",
                            iPatchIx, m_grid.GetPatchCount());
            }
            /*
            			printf("Write %i %i %i %i %i\n",
            				iPatchIx,
            				m_vecGridPatchByteLoc[iPatchIx][0],
            				m_vecGridPatchByteSize[iPatchIx][0],
            				m_vecGridPatchByteLoc[iPatchIx][1],
            				m_vecGridPatchByteSize[iPatchIx][1]);
            */
            const DataContainer & dcGeometric =
                pPatch->GetDataContainerGeometric();
            int nGeometricDataByteSize =
                dcGeometric.GetTotalByteSize();
            const char * pGeometricData =
                (const char *)(dcGeometric.GetPointer());

            m_ofsActiveOutput.seekp(
                posRefFile + m_vecGridPatchByteLoc[iPatchIx][0]);
            m_ofsActiveOutput.write(
                pGeometricData, m_vecGridPatchByteSize[iPatchIx][0]);

            const DataContainer & dcActiveState =
                pPatch->GetDataContainerActiveState();
            int nActiveStateDataByteSize =
                dcActiveState.GetTotalByteSize();
            const char * pActiveStateData =
                (const char *)(dcActiveState.GetPointer());

            m_ofsActiveOutput.seekp(
                posRefFile + m_vecGridPatchByteLoc[iPatchIx][1]);
            m_ofsActiveOutput.write(
                pActiveStateData, m_vecGridPatchByteSize[iPatchIx][1]);
        }

        // Recieve all data objects from neighbors
        int nRemainingMessages =
            2 * (m_grid.GetPatchCount() - m_grid.GetActivePatchCount());

        for (; nRemainingMessages > 0; nRemainingMessages--) {

            // Receive a consolidation message
            MPI_Status status;

            MPI_Recv(
                &(m_vecRecvBuffer[0]),
                m_vecRecvBuffer.GetRows(),
                MPI_CHAR,
                MPI_ANY_SOURCE,
                MPI_ANY_TAG,
                MPI_COMM_WORLD,
                &status);

            // Data type from TAG
            int iDataType = status.MPI_TAG;
            if ((iDataType < 0) || (iDataType >= ExchangeDataType_Count)) {
                _EXCEPTION1("MPI_TAG (%i) out of range", iDataType);
            }

            // Check patch index
            int iPatchIx = *((int*)(&(m_vecRecvBuffer[0])));

            if (iPatchIx > m_vecGridPatchByteLoc.GetRows()) {
                _EXCEPTION2("PatchIndex (%i) out of range [0,%i)",
                            iPatchIx, m_vecGridPatchByteLoc.GetRows());
            }
            /*
            			if (iDataType == 0) {
            				printf("Recv Geo %i %i\n",
            					pPatchIx[0],
            					m_vecGridPatchByteSize[pPatchIx[0]][iDataType]);
            			} else {
            				printf("Recv AcS %i %i\n",
            					pPatchIx[0],
            					m_vecGridPatchByteSize[pPatchIx[0]][iDataType]);
            			}
            */
            m_ofsActiveOutput.seekp(
                posRefFile + m_vecGridPatchByteLoc[iPatchIx][iDataType]);
            m_ofsActiveOutput.write(
                (const char *)(&(m_vecRecvBuffer[0])),
                m_vecGridPatchByteSize[iPatchIx][iDataType]);
        }
    }

    // Barrier
    MPI_Barrier(MPI_COMM_WORLD);

#else
    _EXCEPTIONT("Not implemented without USE_MPI");
#endif
}
void MeshUtilities::FindFaceFromNode(
	const Mesh & mesh,
	const Node & node,
	FindFaceStruct & aFindFaceStruct
) {
	// Reset the FaceStruct
	aFindFaceStruct.vecFaceIndices.clear();
	aFindFaceStruct.vecFaceLocations.clear();
	aFindFaceStruct.loc = Face::NodeLocation_Undefined;

	// Loop through all faces to find overlaps
	// Note: This algorithm can likely be dramatically improved
	for (int l = 0; l < mesh.faces.size(); l++) {
		Face::NodeLocation loc;
		int ixLocation;

		ContainsNode(
			mesh.faces[l],
			mesh.nodes,
			node,
			loc,
			ixLocation);

		if (loc == Face::NodeLocation_Exterior) {
			continue;
		}

#ifdef VERBOSE
		printf("%i\n", l);
		printf("n: %1.5e %1.5e %1.5e\n", node.x, node.y, node.z);
		printf("n0: %1.5e %1.5e %1.5e\n",
			mesh.nodes[mesh.faces[l][0]].x,
			mesh.nodes[mesh.faces[l][0]].y,
			mesh.nodes[mesh.faces[l][0]].z);
		printf("n1: %1.5e %1.5e %1.5e\n",
			mesh.nodes[mesh.faces[l][1]].x,
			mesh.nodes[mesh.faces[l][1]].y,
			mesh.nodes[mesh.faces[l][1]].z);
		printf("n2: %1.5e %1.5e %1.5e\n",
			mesh.nodes[mesh.faces[l][2]].x,
			mesh.nodes[mesh.faces[l][2]].y,
			mesh.nodes[mesh.faces[l][2]].z);
		printf("n3: %1.5e %1.5e %1.5e\n",
			mesh.nodes[mesh.faces[l][3]].x,
			mesh.nodes[mesh.faces[l][3]].y,
			mesh.nodes[mesh.faces[l][3]].z);
#endif

		if (aFindFaceStruct.loc == Face::NodeLocation_Undefined) {
			aFindFaceStruct.loc = loc;
		}

		// Node is in the interior of this face
		if (loc == Face::NodeLocation_Interior) {
			if (loc != aFindFaceStruct.loc) {
				_EXCEPTIONT("No consensus on location of Node");
			}

			aFindFaceStruct.vecFaceIndices.push_back(l);
			aFindFaceStruct.vecFaceLocations.push_back(ixLocation);
			break;
		}

		// Node is on the edge of this face
		if (loc == Face::NodeLocation_Edge) {
			if (loc != aFindFaceStruct.loc) {
				_EXCEPTIONT("No consensus on location of Node");
			}

			aFindFaceStruct.vecFaceIndices.push_back(l);
			aFindFaceStruct.vecFaceLocations.push_back(ixLocation);
		}

		// Node is at the corner of this face
		if (loc == Face::NodeLocation_Corner) {
			if (loc != aFindFaceStruct.loc) {
				_EXCEPTIONT("No consensus on location of Node");
			}

			aFindFaceStruct.vecFaceIndices.push_back(l);
			aFindFaceStruct.vecFaceLocations.push_back(ixLocation);
		}
	}

	// Edges can only have two adjacent Faces
	if (aFindFaceStruct.loc == Face::NodeLocation_Edge) {
		if (aFindFaceStruct.vecFaceIndices.size() != 2) {
			printf("n: %1.5e %1.5e %1.5e\n", node.x, node.y, node.z);
			_EXCEPTION2("Node found on edge with %i neighboring face(s) (%i)",
				aFindFaceStruct.vecFaceIndices.size(),
				(int)(aFindFaceStruct.vecFaceIndices.size()));
		}
	}

	// Corners must have at least three adjacent Faces
	if (aFindFaceStruct.loc == Face::NodeLocation_Corner) {
		if (aFindFaceStruct.vecFaceIndices.size() < 3) {
			printf("n: %1.5e %1.5e %1.5e\n", node.x, node.y, node.z);
			_EXCEPTION1("Two Faced corner detected (%i)",
				(int)(aFindFaceStruct.vecFaceIndices.size()));
		}
	}
}
bool OutputManagerReference::OpenFile(
	const std::string & strFileName
) {
#ifdef TEMPEST_NETCDF
	// Determine processor rank; only proceed if root node
	int nRank = 0;

#ifdef TEMPEST_MPIOMP
	MPI_Comm_rank(MPI_COMM_WORLD, &nRank);
#endif

	// The active model
	const Model & model = m_grid.GetModel();

	// Open NetCDF file on root process
	if (nRank == 0) {

		// Check for existing NetCDF file
		if (m_pActiveNcOutput != NULL) {
			_EXCEPTIONT("NetCDF file already open");
		}

		// Append .nc extension to file
		std::string strNcFileName = strFileName + ".nc";

		// Open new NetCDF file
		m_pActiveNcOutput = new NcFile(strNcFileName.c_str(), NcFile::Replace);
		if (m_pActiveNcOutput == NULL) {
			_EXCEPTION1("Error opening NetCDF file \"%s\"",
				strNcFileName.c_str());
		}
		if (!m_pActiveNcOutput->is_valid()) {
			_EXCEPTION1("Error opening NetCDF file \"%s\"",
				strNcFileName.c_str());
		}

		// Create nodal time dimension
		NcDim * dimTime = m_pActiveNcOutput->add_dim("time");
		if (dimTime == NULL) {
			_EXCEPTIONT("Error creating \"time\" dimension");
		}

		m_varTime = m_pActiveNcOutput->add_var("time", ncDouble, dimTime);
		if (m_varTime == NULL) {
			_EXCEPTIONT("Error creating \"time\" variable");
		}

		std::string strUnits =
			"days since " + model.GetStartTime().ToDateString();

		std::string strCalendarName = model.GetStartTime().GetCalendarName();

		m_varTime->add_att("long_name", "time");
		m_varTime->add_att("units", strUnits.c_str());
		m_varTime->add_att("calendar", strCalendarName.c_str());
		m_varTime->add_att("bounds", "time_bnds");

		// Create levels dimension
		NcDim * dimLev =
			m_pActiveNcOutput->add_dim("lev", m_dREtaCoord.GetRows());

		// Create interfaces dimension
		NcDim * dimILev =
			m_pActiveNcOutput->add_dim("ilev", m_grid.GetRElements()+1);

		// Create latitude dimension
		NcDim * dimLat =
			m_pActiveNcOutput->add_dim("lat", m_nYReference);

		// Create longitude dimension
		NcDim * dimLon =
			m_pActiveNcOutput->add_dim("lon", m_nXReference);

		// Output physical constants
		const PhysicalConstants & phys = model.GetPhysicalConstants();

		m_pActiveNcOutput->add_att("earth_radius", phys.GetEarthRadius());
		m_pActiveNcOutput->add_att("g", phys.GetG());
		m_pActiveNcOutput->add_att("omega", phys.GetOmega());
		m_pActiveNcOutput->add_att("alpha", phys.GetAlpha());
		m_pActiveNcOutput->add_att("Rd", phys.GetR());
		m_pActiveNcOutput->add_att("Cp", phys.GetCp());
		m_pActiveNcOutput->add_att("T0", phys.GetT0());
		m_pActiveNcOutput->add_att("P0", phys.GetP0());
		m_pActiveNcOutput->add_att("rho_water", phys.GetRhoWater());
		m_pActiveNcOutput->add_att("Rvap", phys.GetRvap());
		m_pActiveNcOutput->add_att("Mvap", phys.GetMvap());
		m_pActiveNcOutput->add_att("Lvap", phys.GetLvap());

		// Output grid parameters
		m_pActiveNcOutput->add_att("Ztop", m_grid.GetZtop());

		// Output equation set
		const EquationSet & eqn = model.GetEquationSet();

		m_pActiveNcOutput->add_att("equation_set", eqn.GetName().c_str());

		// Create variables
		for (int c = 0; c < eqn.GetComponents(); c++) {
			if ((m_fOutputAllVarsOnNodes) ||
				(m_grid.GetVarLocation(c) == DataLocation_Node)
			) {
				m_vecComponentVar.push_back(
					m_pActiveNcOutput->add_var(
						eqn.GetComponentShortName(c).c_str(),
						ncDouble, dimTime, dimLev, dimLat, dimLon));
			} else {
				m_vecComponentVar.push_back(
					m_pActiveNcOutput->add_var(
						eqn.GetComponentShortName(c).c_str(),
						ncDouble, dimTime, dimILev, dimLat, dimLon));
			}
		}

		for (int c = 0; c < eqn.GetTracers(); c++) {
			m_vecTracersVar.push_back(
				m_pActiveNcOutput->add_var(
					eqn.GetTracerShortName(c).c_str(),
					ncDouble, dimTime, dimLev, dimLat, dimLon));
		}

		// Vorticity variable
		if (m_fOutputVorticity) {
			m_varVorticity =
				m_pActiveNcOutput->add_var(
					"ZETA", ncDouble, dimTime, dimLev, dimLat, dimLon);
		}

		// Divergence variable
		if (m_fOutputDivergence) {
			m_varDivergence =
				m_pActiveNcOutput->add_var(
					"DELTA", ncDouble, dimTime, dimLev, dimLat, dimLon);
		}

		// Temperature variable
		if (m_fOutputTemperature) {
			m_varTemperature =
				m_pActiveNcOutput->add_var(
					"T", ncDouble, dimTime, dimLev, dimLat, dimLon);
		}

		// Surface pressure variable
		if (m_fOutputSurfacePressure) {
			m_varSurfacePressure =
				m_pActiveNcOutput->add_var(
					"PS", ncDouble, dimTime, dimLat, dimLon);
		}

		// Richardson number variable
		if (m_fOutputRichardson) {
			m_varRichardson =
				m_pActiveNcOutput->add_var(
					"Ri", ncDouble, dimTime, dimLev, dimLat, dimLon);
		}

		// User data variables
		const UserDataMeta & metaUserData = model.GetUserDataMeta();

		m_vecUserData2DVar.resize(metaUserData.GetUserData2DItemCount());
		for (int i = 0; i < metaUserData.GetUserData2DItemCount(); i++) {
			m_vecUserData2DVar[i] =
				m_pActiveNcOutput->add_var(
					metaUserData.GetUserData2DItemName(i).c_str(),
					ncDouble, dimTime, dimLat, dimLon);
		}

		// Output longitudes and latitudes
		NcVar * varLon = m_pActiveNcOutput->add_var("lon", ncDouble, dimLon);
		NcVar * varLat = m_pActiveNcOutput->add_var("lat", ncDouble, dimLat);

		varLon->put(m_dXCoord, m_dXCoord.GetRows());
		varLat->put(m_dYCoord, m_dYCoord.GetRows());

		varLon->add_att("long_name", "longitude");
		varLon->add_att("units", "degrees_east");

		varLat->add_att("long_name", "latitude");
		varLat->add_att("units", "degrees_north");

		// Output levels
		NcVar * varLev =
			m_pActiveNcOutput->add_var("lev", ncDouble, dimLev);

		varLev->put(
			m_dREtaCoord,
			m_dREtaCoord.GetRows());

		varLev->add_att("long_name", "level");
		varLev->add_att("units", "level");

		// Output interface levels
		NcVar * varILev =
			m_pActiveNcOutput->add_var("ilev", ncDouble, dimILev);

		varILev->put(
			m_grid.GetREtaStretchInterfaces(),
			m_grid.GetREtaStretchInterfaces().GetRows());

		varILev->add_att("long_name", "interface level");
		varILev->add_att("units", "level");

		// Topography variable
		m_varTopography =
			m_pActiveNcOutput->add_var("Zs", ncDouble, dimLat, dimLon);

		// Fresh output file
		m_fFreshOutputFile = true;
	}

#ifdef TEMPEST_MPIOMP
	// Wait for all processes to complete
	MPI_Barrier(MPI_COMM_WORLD);
#endif
#endif

	return true;
}	
int main(int argc, char** argv) {

	NcError error(NcError::verbose_nonfatal);

try {

	// Input file
	std::string strInputFile;

	// Input file list
	std::string strInputFileList;

	// Input file format
	std::string strInputFormat;

	// NetCDF file containing latitude and longitude arrays
	std::string strLatLonFile;

	// Output file (NetCDF)
	std::string strOutputFile;

	// Output variable name
	std::string strOutputVariable;

	// Column in which the longitude index appears
	int iLonIxCol;

	// Column in which the latitude index appears
	int iLatIxCol;

	// Begin latitude
	double dLatBegin;

	// End latitude
	double dLatEnd;

	// Begin longitude
	double dLonBegin;

	// End longitude
	double dLonEnd;

	// Number of latitudes in output
	int nLat;

	// Number of longitudes in output
	int nLon;

	// Parse the command line
	BeginCommandLine()
		CommandLineString(strInputFile, "in", "");
		CommandLineString(strInputFileList, "inlist", "");
		CommandLineStringD(strInputFormat, "in_format", "std", "(std|visit)");
		CommandLineString(strOutputFile, "out", "");
		CommandLineString(strOutputVariable, "outvar", "density");
		CommandLineInt(iLonIxCol, "iloncol", 8);
		CommandLineInt(iLatIxCol, "ilatcol", 9);
		CommandLineDouble(dLatBegin, "lat_begin", -90.0);
		CommandLineDouble(dLatEnd, "lat_end", 90.0);
		CommandLineDouble(dLonBegin, "lon_begin", 0.0);
		CommandLineDouble(dLonEnd, "lon_end", 360.0);
		CommandLineInt(nLat, "nlat", 180);
		CommandLineInt(nLon, "nlon", 360);

		ParseCommandLine(argc, argv);
	EndCommandLine(argv)

	AnnounceBanner();

	// Check input
	if ((strInputFile == "") && (strInputFileList == "")) {
		_EXCEPTIONT("No input file (--in) or (--inlist) specified");
	}
	if ((strInputFile != "") && (strInputFileList != "")) {
		_EXCEPTIONT("Only one input file (--in) or (--inlist) allowed");
	}
	if (strInputFormat != "std") {
		_EXCEPTIONT("UNIMPLEMENTED:  Only \"--in_format std\" supported");
	}

	// Check output
	if (strOutputFile == "") {
		_EXCEPTIONT("No output file (--out) specified");
	}

	// Check output variable
	if (strOutputVariable == "") {
		_EXCEPTIONT("No output variable name (--outvar) specified");
	}

	// Number of latitudes and longitudes
	if (nLat == 0) {
		_EXCEPTIONT("UNIMPLEMENTED: --nlat must be specified currently");
	}
	if (nLon == 0) {
		_EXCEPTIONT("UNIMPLEMENTED: --nlon must be specified currently");
	}

	// Input file list
	std::vector<std::string> vecInputFiles;

	if (strInputFile != "") {
		vecInputFiles.push_back(strInputFile);
	}
	if (strInputFileList != "") {
		GetInputFileList(strInputFileList, vecInputFiles);
	}

	int nFiles = vecInputFiles.size();

	// Density
	DataMatrix<int> nCounts;
	nCounts.Initialize(nLat, nLon);

	// Loop through all files in list
	AnnounceStartBlock("Processing files");

	std::string strBuffer;
	strBuffer.reserve(1024);

	for (int f = 0; f < nFiles; f++) {
		Announce("File \"%s\"", vecInputFiles[f].c_str());

		FILE * fp = fopen(vecInputFiles[f].c_str(), "r");
		if (fp == NULL) {
			_EXCEPTION1("Unable to open input file \"%s\"",
				vecInputFiles[f].c_str());
		}

		for (;;) {

			// Read in the next line
			fgets(&(strBuffer[0]), 1024, fp);

			int nLength = strlen(&(strBuffer[0]));

			// Check for end of file
			if (feof(fp)) {
				break;
			}

			// Check for comment line
			if (strBuffer[0] == '#') {
				continue;
			}

			// Check for new storm
			if (strncmp(&(strBuffer[0]), "start", 5) == 0) {
				continue;
			}

			// Parse line
			double dLon;
			double dLat;

			int iCol = 0;
			int iLast = 0;

			bool fWhitespace = true;

			for (int i = 0; i <= nLength; i++) {
				if ((strBuffer[i] == ' ') ||
					(strBuffer[i] == ',') ||
					(strBuffer[i] == '\t') ||
					(strBuffer[i] == '\0')
				) {
					if (!fWhitespace) {
						if (iCol == iLonIxCol) {
							strBuffer[i] = '\0';
							dLon = atof(&(strBuffer[iLast]));
						}
						if (iCol == iLatIxCol) {
							strBuffer[i] = '\0';
							dLat = atof(&(strBuffer[iLast]));
						}
					}

					fWhitespace = true;

				} else {
					if (fWhitespace) {
						iLast = i;
						iCol++;
					}
					fWhitespace = false;
				}
			}

			// Latitude and longitude index
			int iLon =
				static_cast<int>(static_cast<double>(nLon)
					* (dLon - dLonBegin) / (dLonEnd - dLonBegin));
			int iLat =
				static_cast<int>(static_cast<double>(nLat)
					* (dLat - dLatBegin) / (dLatEnd - dLatBegin));

			if (iLon == (-1)) {
				iLon = 0;
			}
			if (iLon == nLon) {
				iLon = nLon - 1;
			}
			if (iLat == (-1)) {
				iLat = 0;
			}
			if (iLat == nLat) {
				iLat = nLat - 1;
			}

			if ((iLat < 0) || (iLat >= nLat)) {
				_EXCEPTION1("Latitude index (%i) out of range", iLat);
			}
			if ((iLon < 0) || (iLon >= nLon)) {
				_EXCEPTION1("Longitude index (%i) out of range", iLon);
			}

			nCounts[iLat][iLon]++;
		}

		fclose(fp);
	}

	AnnounceEndBlock("Done");

	// Output results
	AnnounceStartBlock("Output results");

	// Load the netcdf output file
	NcFile ncOutput(strOutputFile.c_str(), NcFile::Replace);
	if (!ncOutput.is_valid()) {
		_EXCEPTION1("Unable to open output file \"%s\"",
			strOutputFile.c_str());
	}

	// Create output
	NcDim * dimLat = ncOutput.add_dim("lat", nLat);
	NcDim * dimLon = ncOutput.add_dim("lon", nLon);

	NcVar * varLat = ncOutput.add_var("lat", ncDouble, dimLat);
	NcVar * varLon = ncOutput.add_var("lon", ncDouble, dimLon);

	varLat->add_att("units", "degrees_north");
	varLon->add_att("units", "degrees_east");

	DataVector<double> dLat(nLat);
	DataVector<double> dLon(nLon);

	for (int j = 0; j < nLat; j++) {
		dLat[j] = dLatBegin
			+ (dLatEnd - dLatBegin)
				* (static_cast<double>(j) + 0.5)
				/ static_cast<double>(nLat);
	}
	for (int i = 0; i < nLon; i++) {
		dLon[i] = dLonBegin
			+ (dLonEnd - dLonBegin)
			* (static_cast<double>(i) + 0.5)
			/ static_cast<double>(nLon);
	}

	varLat->put(&(dLat[0]), nLat);
	varLon->put(&(dLon[0]), nLon);

	// Output counts
	NcVar * varCount =
		ncOutput.add_var(
			strOutputVariable.c_str(),
			ncInt,
			dimLat,
			dimLon);

	varCount->put(&(nCounts[0][0]), nLat, nLon);

	ncOutput.close();

	AnnounceEndBlock("Done");

	AnnounceBanner();

} catch(Exception & e) {
	Announce(e.ToString().c_str());
}
}
void CopyNcVar(
	NcFile & ncIn,
	NcFile & ncOut,
	const std::string & strVarName,
	bool fCopyAttributes,
	bool fCopyData
) {
	if (!ncIn.is_valid()) {
		_EXCEPTIONT("Invalid input file specified");
	}
	if (!ncOut.is_valid()) {
		_EXCEPTIONT("Invalid output file specified");
	}
	NcVar * var = ncIn.get_var(strVarName.c_str());
	if (var == NULL) {
		_EXCEPTION1("NetCDF file does not contain variable \"%s\"",
			strVarName.c_str());
	}

	NcVar * varOut;

	std::vector<NcDim *> dimOut;
	dimOut.resize(var->num_dims());

	std::vector<long> counts;
	counts.resize(var->num_dims());

	long nDataSize = 1;

	for (int d = 0; d < var->num_dims(); d++) {
		NcDim * dimA = var->get_dim(d);

		dimOut[d] = ncOut.get_dim(dimA->name());

		if (dimOut[d] == NULL) {
			if (dimA->is_unlimited()) {
				dimOut[d] = ncOut.add_dim(dimA->name());
			} else {
				dimOut[d] = ncOut.add_dim(dimA->name(), dimA->size());
			}

			if (dimOut[d] == NULL) {
				_EXCEPTION2("Failed to add dimension \"%s\" (%i) to file",
					dimA->name(), dimA->size());
			}
		}
		if (dimOut[d]->size() != dimA->size()) {
			if (dimA->is_unlimited() && !dimOut[d]->is_unlimited()) {
				_EXCEPTION2("Mismatch between input file dimension \"%s\" and "
					"output file dimension (UNLIMITED / %i)",
					dimA->name(), dimOut[d]->size());
			} else if (!dimA->is_unlimited() && dimOut[d]->is_unlimited()) {
				_EXCEPTION2("Mismatch between input file dimension \"%s\" and "
					"output file dimension (%i / UNLIMITED)",
					dimA->name(), dimA->size());
			} else if (!dimA->is_unlimited() && !dimOut[d]->is_unlimited()) {
				_EXCEPTION3("Mismatch between input file dimension \"%s\" and "
					"output file dimension (%i / %i)",
					dimA->name(), dimA->size(), dimOut[d]->size());
			}
		}

		counts[d] = dimA->size();
		nDataSize *= counts[d];
	}

	// ncByte / ncChar type
	if ((var->type() == ncByte) || (var->type() == ncChar)) {
		DataVector<char> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		var->get(&(data[0]), &(counts[0]));
		varOut->put(&(data[0]), &(counts[0]));
	}

	// ncShort type
	if (var->type() == ncShort) {
		DataVector<short> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		if (fCopyData) {
			var->get(&(data[0]), &(counts[0]));
			varOut->put(&(data[0]), &(counts[0]));
		}
	}

	// ncInt type
	if (var->type() == ncInt) {
		DataVector<int> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		if (fCopyData) {
			var->get(&(data[0]), &(counts[0]));
			varOut->put(&(data[0]), &(counts[0]));
		}
	}

	// ncFloat type
	if (var->type() == ncFloat) {
		DataVector<float> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		if (fCopyData) {
			var->get(&(data[0]), &(counts[0]));
			varOut->put(&(data[0]), &(counts[0]));
		}
	}

	// ncDouble type
	if (var->type() == ncDouble) {
		DataVector<double> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		if (fCopyData) {
			var->get(&(data[0]), &(counts[0]));
			varOut->put(&(data[0]), &(counts[0]));
		}
	}

	// ncInt64 type
	if (var->type() == ncInt64) {
		DataVector<ncint64> data;
		data.Initialize(nDataSize);

		varOut =
			ncOut.add_var(
				var->name(), var->type(),
				dimOut.size(), (const NcDim**)&(dimOut[0]));

		if (varOut == NULL) {
			_EXCEPTION1("Cannot create variable \"%s\"", var->name());
		}

		if (fCopyData) {
			var->get(&(data[0]), &(counts[0]));
			varOut->put(&(data[0]), &(counts[0]));
		}
	}

	// Check output variable exists
	if (varOut == NULL) {
		_EXCEPTION1("Unable to create output variable \"%s\"",
			var->name());
	}

	// Copy attributes
	if (fCopyAttributes) {
		CopyNcVarAttributes(var, varOut);
	}
}
void LegendrePolynomial::AllDerivativeRoots(
	int nDegree,
	double * dRoots
) {
	// Iteration tolerance
	const double IterationTolerance = 1.0e-14;

	// Check for degree 0 or 1
	if ((nDegree == 0) || (nDegree == 1)) {
		return;
	}

	// Check for negative degree
	if (nDegree < 0) {
		_EXCEPTION1("Invalid degree (%i)", nDegree);
	}

	// Check for NULL dRoots pointer
	if (dRoots == NULL) {
		_EXCEPTIONT("NULL pointer passed into AllRoots argument dRoots");
	}

	// Double degree
	double dDegree = static_cast<double>(nDegree);

	// Additional storage for roots
	double * dBuffer = new double[nDegree-1];

	// Set initial estimate
	for (int k = 0; k < nDegree-1; k++) {
		dRoots[k] = (static_cast<double>(k) + 0.5) * 2.0 / (dDegree - 1.0) - 1.0;
	}

	// Refine estimate using Aberth-Ehrlich method
	for (int iter = 0; iter < nDegree + 10; iter++) {
/*
		for (int k = 0; k < nDegree - 1; k++) {
			printf("%i %i: %1.15e\n", iter, k, dRoots[k]);
		}
*/
		int nFoundRoots = 0;

		for (int k = 0; k < nDegree - 1; k++) {
			double dValue;
			double dDerivative;

			EvaluateValueAndDerivative(nDegree, dRoots[k], dValue, dDerivative);

			if (fabs(dDerivative) < IterationTolerance) {
				nFoundRoots++;
				dBuffer[k] = dRoots[k];
				continue;
			}

			double dMod = 0.0;
			for (int l = 0; l < nDegree - 1; l++) {
				if (l == k) {
					continue;
				}

				dMod += 1.0 / (dRoots[k] - dRoots[l]);
			}

			// Second derivative obtained from 
			double dSecondDerivative =
				1.0 / (1.0 - dRoots[k] * dRoots[k])
				* (2.0 * dRoots[k] * dDerivative
					- dDegree * (dDegree + 1.0) * dValue);

			dBuffer[k] = dRoots[k]
				- 1.0 / (dSecondDerivative / dDerivative - dMod);
		}

		// Copy buffer to roots
		memcpy(dRoots, dBuffer, (nDegree - 1) * sizeof(double));

		// Check if all roots have been found
		if (nFoundRoots == nDegree - 1) {
			break;
		}
	}

	// Sort roots
	std::sort(dRoots, dRoots + nDegree - 1);

	// Delete buffer
	delete[] dBuffer;
}
int main(int argc, char ** argv){
  NcError error(NcError::verbose_nonfatal);

  try{
    std::string inFile;
    std::string outFile;
    std::string varName;
    std::string inList;
//    bool calcStdDev;

    BeginCommandLine()
      CommandLineString(inFile, "in", "");
      CommandLineString(inList, "inlist","");
      CommandLineString(varName, "var", "");
      CommandLineString(outFile, "out", "");
  //    CommandLineBool(calcStdDev, "std");
      ParseCommandLine(argc, argv);
    EndCommandLine(argv)
    AnnounceBanner();
  

    if ((inFile != "") && (inList != "")){
      _EXCEPTIONT("Can only open one file (--in) or list (--inlist).");
    }

    //file list vector
    std::vector<std::string> vecFiles;
    if (inFile != ""){
      vecFiles.push_back(inFile);
    }
    if (inList != ""){
      GetInputFileList(inList,vecFiles);
    }

    //open up first file
    NcFile readin(vecFiles[0].c_str());
    if (!readin.is_valid()){
      _EXCEPTION1("Unable to open file %s for reading",\
        vecFiles[0].c_str());
    }
    int tLen,latLen,lonLen;

    NcDim * time = readin.get_dim("time");
    tLen = time->size();
    NcVar * timeVar = readin.get_var("time");

    NcDim * lat = readin.get_dim("lat");
    latLen = lat->size();
    NcVar * latVar = readin.get_var("lat");

    NcDim * lon = readin.get_dim("lon");
    lonLen = lon->size();
    NcVar * lonVar = readin.get_var("lon");

    //read input variable
    NcVar * inVar = readin.get_var(varName.c_str());
    //Create output matrix
    DataMatrix<double> outMat(latLen,lonLen);
    densCalc(inVar,outMat);
    //Option for calculating the yearly standard deviation 
 /*   if (calcStdDev){
      for (int a=0; a<latLen; a++){
        for (int b=0; b<lonLen; b++){
          storeMat[0][a][b] = outMat[a][b];
        }
      }
    }
*/
    //If multiple files, add these values to the output
    if (vecFiles.size()>1){
      DataMatrix<double> addMat(latLen,lonLen);
      std::cout<<"There are "<<vecFiles.size()<<" files."<<std::endl;
      for (int v=1; v<vecFiles.size(); v++){
        NcFile addread(vecFiles[v].c_str());
        NcVar * inVar = addread.get_var(varName.c_str());
        densCalc(inVar,addMat);
        for (int a=0; a<latLen; a++){
          for (int b=0; b<lonLen; b++){
            outMat[a][b]+=addMat[a][b];
          }
        }
/*        if (calcStdDev){
          for (int a=0; a<latLen; a++){
            for (int b=0; b<lonLen; b++){
              storeMat[v][a][b] = addMat[a][b];
            }
          }
        }*/
        addread.close(); 
      }
      //Divide output by number of files
      double div = 1./((double) vecFiles.size());
      for (int a=0; a<latLen; a++){
        for (int b=0; b<lonLen; b++){
          outMat[a][b]*=div;
        }
      }
    }
 
    NcFile readout(outFile.c_str(),NcFile::Replace, NULL,0,NcFile::Offset64Bits);
    NcDim * outLat = readout.add_dim("lat", latLen);
    NcDim * outLon = readout.add_dim("lon", lonLen);
    NcVar * outLatVar = readout.add_var("lat",ncDouble,outLat);
    NcVar * outLonVar = readout.add_var("lon",ncDouble,outLon);
    std::cout<<"Copying dimension attributes."<<std::endl;
    copy_dim_var(latVar,outLatVar);
    copy_dim_var(lonVar,outLonVar);

    std::cout<<"Creating density variable."<<std::endl;

    NcVar * densVar = readout.add_var("dens",ncDouble,outLat,outLon);
    densVar->set_cur(0,0);
    densVar->put((&outMat[0][0]),latLen,lonLen);

/*    if (calcStdDev){
      NcVar * stdDevVar = readout.add_var("stddev", ncDouble,outLat,outLon);
      DataMatrix<double> stdDevMat(latLen,lonLen);
      yearlyStdDev(storeMat,vecFiles.size(),latLen,lonLen,stdDevMat);
      stdDevVar->set_cur(0,0);
      stdDevVar->put(&(stdDevMat[0][0]),latLen,lonLen);
      std::cout<<" created sd variable"<<std::endl;

    }
*/
    readout.close();
    readin.close();
  } 
  catch (Exception &e){
    std::cout<<e.ToString()<<std::endl;
  }
}
Example #24
0
void GridPatchCSGLL::EvaluateGeometricTerms() {

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

	// 2D equation set
	bool fIs2DEquationSet = false;
	if (m_grid.GetModel().GetEquationSet().GetDimensionality() == 2) {
		fIs2DEquationSet = true;
	}

	if ((fIs2DEquationSet) && (m_grid.GetZtop() != 1.0)) {
		_EXCEPTIONT("Ztop must be 1.0 for 2D equation sets");
	}

	// Obtain Gauss Lobatto quadrature nodes and weights
	DataArray1D<double> dGL;
	DataArray1D<double> dWL;

	GaussLobattoQuadrature::GetPoints(m_nHorizontalOrder, 0.0, 1.0, dGL, dWL);

	// Obtain normalized areas in the vertical
	const DataArray1D<double> & dWNode =
		m_grid.GetREtaLevelsNormArea();
	const DataArray1D<double> & dWREdge =
		m_grid.GetREtaInterfacesNormArea();

	// Verify that normalized areas are correct
	double dWNodeSum = 0.0;
	for (int k = 0; k < dWNode.GetRows(); k++) {
		dWNodeSum += dWNode[k];
	}
	if (fabs(dWNodeSum - 1.0) > 1.0e-13) {
		_EXCEPTION1("Error in normalized areas (%1.15e)", dWNodeSum);
	}

	if (m_grid.GetVerticalStaggering() !=
	    Grid::VerticalStaggering_Interfaces
	) {
		double dWREdgeSum = 0.0;
		for (int k = 0; k < dWREdge.GetRows(); k++) {
			dWREdgeSum += dWREdge[k];
		}
		if (fabs(dWREdgeSum - 1.0) > 1.0e-13) {
			_EXCEPTION1("Error in normalized areas (%1.15e)", dWREdgeSum);
		}
	}

	// Derivatives of basis functions
	GridCSGLL & gridCSGLL = dynamic_cast<GridCSGLL &>(m_grid);

	const DataArray2D<double> & dDxBasis1D = gridCSGLL.GetDxBasis1D();

	// Initialize the Coriolis force at each node
	for (int i = 0; i < m_box.GetATotalWidth(); i++) {
	for (int j = 0; j < m_box.GetBTotalWidth(); j++) {
		m_dataCoriolisF[i][j] = 2.0 * phys.GetOmega() * sin(m_dataLat[i][j]);
	}
	}

	// Initialize metric in terrain-following coords
	for (int a = 0; a < GetElementCountA(); a++) {
	for (int b = 0; b < GetElementCountB(); b++) {

	for (int i = 0; i < m_nHorizontalOrder; i++) {
	for (int j = 0; j < m_nHorizontalOrder; j++) {

		// Nodal points
		int iElementA = m_box.GetAInteriorBegin() + a * m_nHorizontalOrder;
		int iElementB = m_box.GetBInteriorBegin() + b * m_nHorizontalOrder;

		int iA = iElementA + i;
		int iB = iElementB + j;

		// Gnomonic coordinates
		double dX = tan(m_dANode[iA]);
		double dY = tan(m_dBNode[iB]);
		double dDelta2 = (1.0 + dX * dX + dY * dY);
		double dDelta = sqrt(dDelta2);

		// Topography height and its derivatives
		double dZs = m_dataTopography[iA][iB];
		double dDaZs = m_dataTopographyDeriv[0][iA][iB];
		double dDbZs = m_dataTopographyDeriv[1][iA][iB];

		// 2D equations
		if (fIs2DEquationSet) {
			dZs = 0.0;
			dDaZs = 0.0;
			dDbZs = 0.0;
		}

		// Initialize 2D Jacobian
		m_dataJacobian2D[iA][iB] =
			(1.0 + dX * dX) * (1.0 + dY * dY) / (dDelta * dDelta * dDelta);

		m_dataJacobian2D[iA][iB] *=
			  phys.GetEarthRadius()
			* phys.GetEarthRadius();

		// Initialize 2D contravariant metric
		double dContraMetricScale = 
			dDelta2 / (1.0 + dX * dX) / (1.0 + dY * dY)
			/ (phys.GetEarthRadius() * phys.GetEarthRadius());

		m_dataContraMetric2DA[iA][iB][0] =
			dContraMetricScale * (1.0 + dY * dY);
		m_dataContraMetric2DA[iA][iB][1] =
			dContraMetricScale * dX * dY;

		m_dataContraMetric2DB[iA][iB][0] =
			dContraMetricScale * dX * dY;
		m_dataContraMetric2DB[iA][iB][1] =
			dContraMetricScale * (1.0 + dX * dX);

		// Initialize 2D covariant metric
		double dCovMetricScale =
			phys.GetEarthRadius() * phys.GetEarthRadius()
			* (1.0 + dX * dX) * (1.0 + dY * dY)
			/ (dDelta2 * dDelta2);

		m_dataCovMetric2DA[iA][iB][0] =
			dCovMetricScale * (1.0 + dX * dX);
		m_dataCovMetric2DA[iA][iB][1] =
			dCovMetricScale * (- dX * dY);

		m_dataCovMetric2DB[iA][iB][0] =
			dCovMetricScale * (- dX * dY);
		m_dataCovMetric2DB[iA][iB][1] =
			dCovMetricScale * (1.0 + dY * dY);

		// Vertical coordinate transform and its derivatives
		for (int k = 0; k < m_grid.GetRElements(); k++) {

			// Gal-Chen and Somerville (1975) linear terrain-following coord
			double dREta = m_grid.GetREtaLevel(k);
/*
			double dREtaStretch;
			double dDxREtaStretch;
			m_grid.EvaluateVerticalStretchF(
				dREta, dREtaStretch, dDxREtaStretch);

			double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;
			double dDaR = (1.0 - dREtaStretch) * dDaZs;
			double dDbR = (1.0 - dREtaStretch) * dDbZs;
			double dDxR = (m_grid.GetZtop() - dZs) * dDxREtaStretch;
*/

			double dZ = dZs + (m_grid.GetZtop() - dZs) * dREta;
			double dDaR = (1.0 - dREta) * dDaZs;
			double dDbR = (1.0 - dREta) * dDbZs;
			double dDxR = (m_grid.GetZtop() - dZs);

			// Calculate pointwise Jacobian
			m_dataJacobian[k][iA][iB] = dDxR * m_dataJacobian2D[iA][iB];

			// Element area associated with each model level GLL node
			m_dataElementAreaNode[k][iA][iB] =
				m_dataJacobian[k][iA][iB]
				* dWL[i] * GetElementDeltaA()
				* dWL[j] * GetElementDeltaB()
				* dWNode[k];

			// Contravariant metric components
			m_dataContraMetricA[k][iA][iB][0] =
				m_dataContraMetric2DA[iA][iB][0];
			m_dataContraMetricA[k][iA][iB][1] =
				m_dataContraMetric2DA[iA][iB][1];
			m_dataContraMetricA[k][iA][iB][2] =
				- dContraMetricScale / dDxR * (
					(1.0 + dY * dY) * dDaR + dX * dY * dDbR);

			m_dataContraMetricB[k][iA][iB][0] =
				m_dataContraMetric2DB[iA][iB][0];
			m_dataContraMetricB[k][iA][iB][1] =
				m_dataContraMetric2DB[iA][iB][1];
			m_dataContraMetricB[k][iA][iB][2] =
				- dContraMetricScale / dDxR * (
					dX * dY * dDaR + (1.0 + dX * dX) * dDbR);

			m_dataContraMetricXi[k][iA][iB][0] =
				m_dataContraMetricA[k][iA][iB][2];
			m_dataContraMetricXi[k][iA][iB][1] =
				m_dataContraMetricB[k][iA][iB][2];
			m_dataContraMetricXi[k][iA][iB][2] =
				  1.0 / (dDxR * dDxR)
				- 1.0 / dDxR * (
					  m_dataContraMetricXi[k][iA][iB][0] * dDaR
					+ m_dataContraMetricXi[k][iA][iB][1] * dDbR);

			// Derivatives of the vertical coordinate transform
			m_dataDerivRNode[k][iA][iB][0] = dDaR;
			m_dataDerivRNode[k][iA][iB][1] = dDbR;
			m_dataDerivRNode[k][iA][iB][2] = dDxR;
		}

		// Metric terms at vertical interfaces
		for (int k = 0; k <= m_grid.GetRElements(); k++) {

			// Gal-Chen and Somerville (1975) linear terrain-following coord
			double dREta = m_grid.GetREtaInterface(k);
/*
			double dREtaStretch;
			double dDxREtaStretch;
			m_grid.EvaluateVerticalStretchF(
				dREta, dREtaStretch, dDxREtaStretch);

			double dZ = dZs + (m_grid.GetZtop() - dZs) * dREtaStretch;

			double dDaR = (1.0 - dREtaStretch) * dDaZs;
			double dDbR = (1.0 - dREtaStretch) * dDbZs;
			double dDxR = (m_grid.GetZtop() - dZs) * dDxREtaStretch;
*/
			double dZ = dZs + (m_grid.GetZtop() - dZs) * dREta;
			double dDaR = (1.0 - dREta) * dDaZs;
			double dDbR = (1.0 - dREta) * dDbZs;
			double dDxR = (m_grid.GetZtop() - dZs);

			// Calculate pointwise Jacobian
			m_dataJacobianREdge[k][iA][iB] =
				(1.0 + dX * dX) * (1.0 + dY * dY) / (dDelta * dDelta * dDelta);

			m_dataJacobianREdge[k][iA][iB] *=
				dDxR
				* phys.GetEarthRadius()
				* phys.GetEarthRadius();

			// Element area associated with each model interface GLL node
			m_dataElementAreaREdge[k][iA][iB] =
				m_dataJacobianREdge[k][iA][iB]
				* dWL[i] * GetElementDeltaA()
				* dWL[j] * GetElementDeltaB()
				* dWREdge[k];

			// Contravariant metric (alpha)
			m_dataContraMetricAREdge[k][iA][iB][0] =
				m_dataContraMetric2DA[iA][iB][0];
			m_dataContraMetricAREdge[k][iA][iB][1] =
				m_dataContraMetric2DA[iA][iB][1];
			m_dataContraMetricAREdge[k][iA][iB][2] =
				- dContraMetricScale / dDxR * (
					(1.0 + dY * dY) * dDaR + dX * dY * dDbR);

			// Contravariant metric (beta)
			m_dataContraMetricBREdge[k][iA][iB][0] =
				m_dataContraMetric2DB[iA][iB][0];
			m_dataContraMetricBREdge[k][iA][iB][1] =
				m_dataContraMetric2DB[iA][iB][1];
			m_dataContraMetricBREdge[k][iA][iB][2] =
				- dContraMetricScale / dDxR * (
					dX * dY * dDaR + (1.0 + dX * dX) * dDbR);

			// Contravariant metric (xi)
			m_dataContraMetricXiREdge[k][iA][iB][0] =
				- dContraMetricScale / dDxR * (
					(1.0 + dY * dY) * dDaR + dX * dY * dDbR);

			m_dataContraMetricXiREdge[k][iA][iB][1] =
				- dContraMetricScale / dDxR * (
					dX * dY * dDaR + (1.0 + dX * dX) * dDbR);

			m_dataContraMetricXiREdge[k][iA][iB][2] =
				  1.0 / (dDxR * dDxR)
				- 1.0 / dDxR * (
					  m_dataContraMetricXiREdge[k][iA][iB][0] * dDaR
					+ m_dataContraMetricXiREdge[k][iA][iB][1] * dDbR);

			// Derivatives of the vertical coordinate transform
			m_dataDerivRREdge[k][iA][iB][0] = dDaR;
			m_dataDerivRREdge[k][iA][iB][1] = dDbR;
			m_dataDerivRREdge[k][iA][iB][2] = dDxR;
		}
	}
	}

	}
	}
}