int main(int argc, char *argv[])
{
	//vector<rPowers> PowerTable;
	int Omega, NumShortTerms, Ordering, IsTriplet, ShPower;
	double Alpha, Beta, Gamma, Mu, Lambda1, Lambda2, Lambda3, Kappa;
	double **PhiHPhi, **PhiPhi;
	vector <double> B(1, 0.0), ARow(1, 0.0), ShortTerms;
	double SLS = 0.0, SLC = 0.0;
	QuadPoints q;
	int sf, l;
	double r2Cusp, r3Cusp;
	int Node = 0, TotalNodes = 1;
	ifstream ParameterFile, FileShortRange;
	ofstream OutFile;
	//int NodeStart, NodeEnd;
	time_t TimeStart, TimeEnd;
#ifdef USE_MPI
	char ProcessorName[MPI_MAX_PROCESSOR_NAME];
	MPI_Status MpiStatus;
	int MpiError, ProcNameLen;
#endif

	//@TODO: Will MPI time be different?
	TimeStart = time(NULL);
	//omp_set_num_threads(1);

	// Initialize global constants.
	PI = 3.1415926535897932384626433832795029L;

	if (argc < 5) {
		cerr << "Not enough parameters on the command line." << endl;
		cerr << "Usage: Scattering kappa parameterfile.txt shortrangefile.psh results.txt" << endl;
		cout << endl;
		exit(1);
	}
	cout << setprecision(18);
	cout.setf(ios::showpoint);

	// MPI initialization
	//@TODO: Check MpiError.
#ifdef USE_MPI
	MpiError = MPI_Init(&argc, &argv);  // All MPI programs start with MPI_Init; all 'N' processes exist thereafter.
	MpiError = MPI_Comm_size(MPI_COMM_WORLD, &TotalNodes);  // Find out how big the SPMD world is
	MpiError = MPI_Comm_rank(MPI_COMM_WORLD, &Node);  // and what this process's rank is.
	MpiError = MPI_Get_processor_name(ProcessorName, &ProcNameLen);
	string LogName;
	if (argc > 5)
		LogName = argv[5];
	else
		LogName = "test.log";
	//MpiError = MPI_File_open(MPI_COMM_WORLD, (char*)LogName.c_str(), MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &MpiLog);
	//cout << "Node " << Node << " of " << TotalNodes << " on " << ProcessorName << endl;

	// The following code here just shows what the nodes are and how many threads each has.
	stringstream ThreadStringStream;
	int ThreadStrLen;
	int MaxThreads = omp_get_max_threads();
	ThreadStringStream << MaxThreads << " threads on Node " << Node << " of " << TotalNodes << " on " << ProcessorName;
	if (Node == 0) {
		cout << endl << ThreadStringStream.str() << endl;
		for (int i = 1; i < TotalNodes; i++) {
			MpiError = MPI_Recv(&ThreadStrLen, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &MpiStatus);
			char *StringStream = new char[ThreadStrLen+1];
			MpiError = MPI_Recv(StringStream, ThreadStrLen, MPI_CHAR, i, 0, MPI_COMM_WORLD, &MpiStatus);
			StringStream[ThreadStrLen] = NULL;
			cout << StringStream << endl;
		}
		cout << endl;
	}
	else {
		ThreadStrLen = ThreadStringStream.str().length();
		const char *ThreadString = ThreadStringStream.str().c_str();
		MpiError = MPI_Send(&ThreadStrLen, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send((void*)ThreadString, ThreadStrLen, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
	}
#else
	Node = 0;
#endif

	if (Node == 0) {
		ParameterFile.open(argv[2]);
		OutFile.open(argv[4]);
		if (!ParameterFile.is_open()) {
			cout << "Could not open parameter file...exiting." << endl;
			FinishMPI();
			exit(3);
		}
		if (!OutFile.is_open()) {
			cout << "Could not open output file...exiting." << endl;
			FinishMPI();
			exit(4);
		}
		OutFile << setprecision(18);
		OutFile.setf(ios::showpoint);
		ShowDateTime(OutFile);

		ReadParamFile(ParameterFile, q, Mu, ShPower, Lambda1, Lambda2, Lambda3, r2Cusp, r3Cusp);

		// Read in short-range short-range elements.  These have already been calculated by the PsHBound program.
		//  We are reading in only the binary versions (they were originally text files).
		//
		FileShortRange.open(argv[3], ios::in | ios::binary);
		if (FileShortRange.fail()) {
			cerr << "Unable to open file " << argv[3] << " for reading." << endl;
			FinishMPI();
			exit(2);
		}

		// Create short-range short-range terms
		//
		// Read in omega and nonlinear parameters.
		if (!ReadShortHeader(FileShortRange, Omega, IsTriplet, Ordering, NumShortTerms, Alpha, Beta, Gamma, l)) {
			cerr << argv[3] << " is not a valid Ps-H short-range file...exiting." << endl;
			FinishMPI();
			exit(3);
		}

		// Calculate number of terms for a given omega. Do we need to compare to the one in the short-range file above?
		NumShortTerms = CalcPowerTableSize(Omega);

		Kappa = atof(argv[1]);

		if (IsTriplet == 0)	sf = 1;
		else if (IsTriplet == 1) sf = -1;
		else {
			cout << "IsTriplet parameter incorrect in " << argv[3] << endl;
			exit(6);
		}

		WriteHeader(OutFile, l, IsTriplet);

		cout << "Omega: " << Omega << endl;
		cout << "Number of terms: " << NumShortTerms << endl;
		cout << "Alpha: " << Alpha << "  Beta: " << Beta << "  Gamma: " << Gamma << endl;
		cout << "Mu: " << Mu << endl;
		cout << "Shielding power: " << ShPower << endl;
		cout << "Kappa: " << Kappa << endl;
		cout << "Lambda: " << Lambda1 << " " << Lambda2 << " " << Lambda3 << endl;

		cout << endl << "Number of quadrature points" << endl;
		cout << "Long-long:                     " << q.LongLong_r1 << " " << q.LongLong_r2Leg << " " << q.LongLong_r2Lag << " " << q.LongLong_r3Leg << " " << q.LongLong_r3Lag << " " << q.LongLong_r12 << " " << q.LongLong_r13 << " " << q.LongLong_phi23 << endl;
		cout << "Long-long 2/r23 term:          " << q.LongLongr23_r1 << " " << q.LongLongr23_r2Leg << " " << q.LongLongr23_r2Lag << " " << q.LongLongr23_r3Leg << " " << q.LongLongr23_r3Lag << " " << q.LongLongr23_phi12 << " " << q.LongLongr23_r13 << " " << q.LongLongr23_r23 << endl;
		cout << "Short-long with qi = 0:        " << q.ShortLong_r1 << " " << q.ShortLong_r2Leg << " " << q.ShortLong_r2Lag << " " << q.ShortLong_r3Leg << " " << q.ShortLong_r3Lag << " " << q.ShortLong_r12 << " " << q.ShortLong_r13 << " " << q.ShortLong_phi23 << endl;
		cout << "Short-long 2/r23 with qi = 0:  " << q.ShortLongr23_r1 << " " << q.ShortLongr23_r2Leg << " " << q.ShortLongr23_r2Lag << " " << q.ShortLongr23_r3Leg << " " << q.ShortLongr23_r3Lag << " " << q.ShortLongr23_r12 << " " << q.ShortLongr23_phi13 << " " << q.ShortLongr23_r23 << endl;
		cout << "Short-long (full) with qi > 0: " << q.ShortLongQiGt0_r1 << " " << q.ShortLongQiGt0_r2Leg << " " << q.ShortLongQiGt0_r2Lag << " " << q.ShortLongQiGt0_r3Leg << " " << q.ShortLongQiGt0_r3Lag << " " << q.ShortLongQiGt0_r12 << " " << q.ShortLongQiGt0_r13 << " " << q.ShortLongQiGt0_phi23 << endl;
		cout << endl;
		cout << "Cusp parameters" << endl;
		cout << r2Cusp << " " << r3Cusp << endl;
		cout << endl;

		if (NumShortTerms > 0) {
			// Allocate memory for the overlap matrix and point PhiPhiP to rows of PhiPhi so we
			//  can access it like a 2D array but have it in contiguous memory for LAPACK.
			PhiPhi = new double*[NumShortTerms*2];
			PhiPhi[0] = new double[NumShortTerms*NumShortTerms*4];
			for (int i = 1; i < NumShortTerms*2; i++) {
				PhiPhi[i] = PhiPhi[i-1] + NumShortTerms*2;
			}
			// Read in the <phi|phi> matrix elements.
			FileShortRange.read((char*)PhiPhi[0], NumShortTerms*NumShortTerms*4*sizeof(double));

			// Allocate memory for the <phi|H|phi> matrix and point PhiHPhiP to rows of PhiHPhi so we
			//  can access it like a 2D array but have it in contiguous memory for LAPACK.
			PhiHPhi = new double*[NumShortTerms*2];
			PhiHPhi[0] = new double[NumShortTerms*NumShortTerms*4];
			for (int i = 1; i < NumShortTerms*2; i++) {
				PhiHPhi[i] = PhiHPhi[i-1] + NumShortTerms*2;
			}
			// Read in the <phi|H|phi> matrix elements.
			FileShortRange.read((char*)PhiHPhi[0], NumShortTerms*NumShortTerms*4*sizeof(double));

			// Allocate matrix of short-range - short-range terms.
			ShortTerms.resize(NumShortTerms*NumShortTerms*4);

			//@TODO: Remove next line.
			//memset(ShortTerms, 0, NumShortTerms*NumShortTerms*4*sizeof(double));  // Initialize to all 0.
		}
	}

	//@TODO: Check results of MpiError.
#ifdef USE_MPI
	MpiError = MPI_Bcast(&Omega, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&NumShortTerms, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Ordering, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&IsTriplet, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Mu, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&ShPower, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Kappa, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Lambda1, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Lambda2, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Lambda3, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Alpha, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Beta, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&Gamma, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&r2Cusp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&r3Cusp, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&sf, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&l, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&ShPower, 1, MPI_INT, 0, MPI_COMM_WORLD);
	MpiError = MPI_Bcast(&q, sizeof(q), MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);
#endif


	ARow.resize(NumShortTerms*2+1);
	B.resize(NumShortTerms*2+1);
	//@TODO: Remove next line.
	//memset(ARow, 0, (NumShortTerms+1)*sizeof(double));  // Initialize to all 0.
	//memset(B, 0, (NumShortTerms+1)*sizeof(double));  // Initialize to all 0.


	vector <rPowers> PowerTableQi0, PowerTableQiGt0;
	vector <vector <rPowers> > PowerTableQi0Array(TotalNodes), PowerTableQiGt0Array(TotalNodes);
	vector <double> AResultsQi0, BResultsQi0, AResultsQiGt0, BResultsQiGt0;
	vector <double> AResultsQi0Final, BResultsQi0Final, AResultsQiGt0Final, BResultsQiGt0Final;
	int NumTerms, NumTermsQi0, NumTermsQiGt0;

	NumTerms = CalcPowerTableSize(Omega);

	if (Node == 0) {
		NumTermsQi0 = CalcPowerTableSizeQi0(Omega, Ordering, 0, NumShortTerms);
		NumTermsQiGt0 = CalcPowerTableSizeQiGt0(Omega, Ordering, 0, NumShortTerms);

		// The *2 comes from the 2 types of symmetry
		AResultsQi0.resize(NumTermsQi0*2, 0.0);
		AResultsQiGt0.resize(NumTermsQiGt0*2, 0.0);
		BResultsQi0.resize(NumTermsQi0*2, 0.0);
		BResultsQiGt0.resize(NumTermsQiGt0*2, 0.0);

		AResultsQi0Final.resize(NumTermsQi0*2, 0.0);
		AResultsQiGt0Final.resize(NumTermsQiGt0*2, 0.0);
		BResultsQi0Final.resize(NumTermsQi0*2, 0.0);
		BResultsQiGt0Final.resize(NumTermsQiGt0*2, 0.0);

		PowerTableQi0.resize(NumTermsQi0*2, rPowers(Alpha, Beta, Gamma));
		PowerTableQiGt0.resize(NumTermsQiGt0*2, rPowers(Alpha, Beta, Gamma));
		GenOmegaPowerTableQi0(Omega, l, Ordering, PowerTableQi0, 0, NumShortTerms-1);
		GenOmegaPowerTableQiGt0(Omega, l, Ordering, PowerTableQiGt0, 0, NumShortTerms-1);
	}


#ifdef USE_MPI
	double NumTermsQi0Proc, NumTermsQiGt0Proc;
	vector <int> NumTermsQi0Array(TotalNodes), NumTermsQiGt0Array(TotalNodes);

	MpiError = MPI_Barrier(MPI_COMM_WORLD);
	// Tell all processes what terms they should be evaluating.
	if (Node == 0) {
		NumTermsQi0Proc = (double)NumTermsQi0 / (double)TotalNodes;  //@TODO: Need the typecast?
		NumTermsQiGt0Proc = (double)NumTermsQiGt0 / (double)TotalNodes;  //@TODO: Need the typecast?
		int Qi0Pos = (int)NumTermsQi0Proc, QiGt0Pos = (int)NumTermsQiGt0Proc;
		for (int i = 1; i < TotalNodes; i++) {
			//@TODO: Do we need to save these values in an array?
			NumTermsQi0Array[i] = int(NumTermsQi0Proc * (i+1)) - int(NumTermsQi0Proc * i);
			NumTermsQiGt0Array[i] = int(NumTermsQiGt0Proc * (i+1)) - int(NumTermsQiGt0Proc * i);
			MpiError = MPI_Send(&NumTermsQi0Array[i], 1, MPI_INT, i, 0, MPI_COMM_WORLD);
			MpiError = MPI_Send(&NumTermsQiGt0Array[i], 1, MPI_INT, i, 0, MPI_COMM_WORLD);
			cout << "Node " << i << ": " << NumTermsQi0Array[i] << " " << NumTermsQiGt0Array[i] << endl;

			PowerTableQi0Array[i].resize(NumTermsQi0Array[i]);
			PowerTableQiGt0Array[i].resize(NumTermsQiGt0Array[i]);
			for (int j = 0; j < NumTermsQi0Array[i]; j++, Qi0Pos++) {
				PowerTableQi0Array[i][j] = PowerTableQi0[Qi0Pos];
				//cout << i << ": " << PowerTableQi0[Qi0Pos].ki + PowerTableQi0[Qi0Pos].li + PowerTableQi0[Qi0Pos].mi + PowerTableQi0[Qi0Pos].ni + PowerTableQi0[Qi0Pos].pi + PowerTableQi0[Qi0Pos].qi << " - " <<
				//	PowerTableQi0[Qi0Pos].ki << " " << PowerTableQi0[Qi0Pos].li << " " << PowerTableQi0[Qi0Pos].mi << " " << PowerTableQi0[Qi0Pos].ni << " " << PowerTableQi0[Qi0Pos].pi << " " << PowerTableQi0[Qi0Pos].qi << endl;
			}
#ifdef VERBOSE
			cout << endl;
#endif
			for (int j = 0; j < NumTermsQiGt0Array[i]; j++, QiGt0Pos++) {
				PowerTableQiGt0Array[i][j] = PowerTableQiGt0[QiGt0Pos];
#ifdef VERBOSE
				cout << i << ": " << PowerTableQiGt0[QiGt0Pos].ki + PowerTableQiGt0[QiGt0Pos].li + PowerTableQiGt0[QiGt0Pos].mi + PowerTableQiGt0[QiGt0Pos].ni + PowerTableQiGt0[QiGt0Pos].pi + PowerTableQiGt0[QiGt0Pos].qi << " - " <<
					PowerTableQiGt0[QiGt0Pos].ki << " " << PowerTableQiGt0[QiGt0Pos].li << " " << PowerTableQiGt0[QiGt0Pos].mi << " " << PowerTableQiGt0[QiGt0Pos].ni << " " << PowerTableQiGt0[QiGt0Pos].pi << " " << PowerTableQiGt0[QiGt0Pos].qi << endl;
#endif//VERBOSE
			}

			//@TODO: How safe is this?
			MpiError = MPI_Send(&PowerTableQi0Array[i][0], sizeof(rPowers)*NumTermsQi0Array[i], MPI_BYTE, i, 0, MPI_COMM_WORLD);
			MpiError = MPI_Send(&PowerTableQiGt0Array[i][0], sizeof(rPowers)*NumTermsQiGt0Array[i], MPI_BYTE, i, 0, MPI_COMM_WORLD);
		}

		NumTermsQi0Array[0] = int(NumTermsQi0Proc);
		NumTermsQiGt0Array[0] = int(NumTermsQiGt0Proc);
		NumTermsQi0 = NumTermsQi0Array[0];
		NumTermsQiGt0 = NumTermsQiGt0Array[0];

		//AResultsQi0.resize(NumTermsQi0*2, 0.0);
		//AResultsQiGt0.resize(NumTermsQiGt0*2, 0.0);
		//BResultsQi0.resize(NumTermsQi0*2, 0.0);
		//BResultsQiGt0.resize(NumTermsQiGt0*2, 0.0);

		//@TODO: Temporary?
		int NumTermsQi0Temp = CalcPowerTableSizeQi0(Omega, Ordering, 0, NumShortTerms);
		for (int i = 0; i < NumTermsQi0; i++) {
			PowerTableQi0[NumTermsQi0+i].ki = PowerTableQi0[NumTermsQi0Temp+i].ki;
			PowerTableQi0[NumTermsQi0+i].li = PowerTableQi0[NumTermsQi0Temp+i].li;
			PowerTableQi0[NumTermsQi0+i].mi = PowerTableQi0[NumTermsQi0Temp+i].mi;
			PowerTableQi0[NumTermsQi0+i].ni = PowerTableQi0[NumTermsQi0Temp+i].ni;
			PowerTableQi0[NumTermsQi0+i].pi = PowerTableQi0[NumTermsQi0Temp+i].pi;
			PowerTableQi0[NumTermsQi0+i].qi = PowerTableQi0[NumTermsQi0Temp+i].qi;
			PowerTableQi0[NumTermsQi0+i].alpha = PowerTableQi0[NumTermsQi0Temp+i].alpha;
			PowerTableQi0[NumTermsQi0+i].beta = PowerTableQi0[NumTermsQi0Temp+i].beta;
			PowerTableQi0[NumTermsQi0+i].gamma = PowerTableQi0[NumTermsQi0Temp+i].gamma;
		}
		int NumTermsQiGt0Temp = CalcPowerTableSizeQiGt0(Omega, Ordering, 0, NumShortTerms);
		for (int i = 0; i < NumTermsQiGt0; i++) {
			PowerTableQiGt0[NumTermsQiGt0+i].ki = PowerTableQiGt0[NumTermsQiGt0Temp+i].ki;
			PowerTableQiGt0[NumTermsQiGt0+i].li = PowerTableQiGt0[NumTermsQiGt0Temp+i].li;
			PowerTableQiGt0[NumTermsQiGt0+i].mi = PowerTableQiGt0[NumTermsQiGt0Temp+i].mi;
			PowerTableQiGt0[NumTermsQiGt0+i].ni = PowerTableQiGt0[NumTermsQiGt0Temp+i].ni;
			PowerTableQiGt0[NumTermsQiGt0+i].pi = PowerTableQiGt0[NumTermsQiGt0Temp+i].pi;
			PowerTableQiGt0[NumTermsQiGt0+i].qi = PowerTableQiGt0[NumTermsQiGt0Temp+i].qi;
			PowerTableQiGt0[NumTermsQiGt0+i].alpha = PowerTableQiGt0[NumTermsQiGt0Temp+i].alpha;
			PowerTableQiGt0[NumTermsQiGt0+i].beta = PowerTableQiGt0[NumTermsQiGt0Temp+i].beta;
			PowerTableQiGt0[NumTermsQiGt0+i].gamma = PowerTableQiGt0[NumTermsQiGt0Temp+i].gamma;
		}

		cout << "Node " << 0 << ": " << NumTermsQi0Array[0] << " " << NumTermsQiGt0Array[0] << endl;
		for (int i = 0; i < NumTermsQiGt0; i++) {
			//cout << 0 << ": " << PowerTableQi0[i].ki + PowerTableQi0[i].li + PowerTableQi0[i].mi + PowerTableQi0[i].ni + PowerTableQi0[i].pi + PowerTableQi0[i].qi << " - " <<
			//		PowerTableQi0[i].ki << " " << PowerTableQi0[i].li << " " << PowerTableQi0[i].mi << " " << PowerTableQi0[i].ni << " " << PowerTableQi0[i].pi << " " << PowerTableQi0[i].qi << endl;
#ifdef VERBOSE
			cout << 0 << ": " << PowerTableQiGt0[i].ki + PowerTableQiGt0[i].li + PowerTableQiGt0[i].mi + PowerTableQiGt0[i].ni + PowerTableQiGt0[i].pi + PowerTableQiGt0[i].qi << " - " <<
					PowerTableQiGt0[i].ki << " " << PowerTableQiGt0[i].li << " " << PowerTableQiGt0[i].mi << " " << PowerTableQiGt0[i].ni << " " << PowerTableQiGt0[i].pi << " " << PowerTableQiGt0[i].qi << endl;
#endif//VERBOSE
		}
		cout << endl;
	}
	else {
		MpiError = MPI_Recv(&NumTermsQi0, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);
		MpiError = MPI_Recv(&NumTermsQiGt0, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);

		PowerTableQi0.resize(NumTermsQi0*2);
		PowerTableQiGt0.resize(NumTermsQiGt0*2);
		AResultsQi0.resize(NumTermsQi0*2);
		AResultsQiGt0.resize(NumTermsQiGt0*2);
		BResultsQi0.resize(NumTermsQi0*2);
		BResultsQiGt0.resize(NumTermsQiGt0*2);

		MpiError = MPI_Recv(&PowerTableQi0[0], sizeof(rPowers)*NumTermsQi0, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);
		MpiError = MPI_Recv(&PowerTableQiGt0[0], sizeof(rPowers)*NumTermsQiGt0, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);

		// Create phi2 terms
		for (int i = 0; i < NumTermsQi0; i++) {
			PowerTableQi0[NumTermsQi0+i].ki = PowerTableQi0[i].ki - l;
			PowerTableQi0[NumTermsQi0+i].li = PowerTableQi0[i].li + l;
			PowerTableQi0[NumTermsQi0+i].mi = PowerTableQi0[i].mi;
			PowerTableQi0[NumTermsQi0+i].ni = PowerTableQi0[i].ni;
			PowerTableQi0[NumTermsQi0+i].pi = PowerTableQi0[i].pi;
			PowerTableQi0[NumTermsQi0+i].qi = PowerTableQi0[i].qi;
			PowerTableQi0[NumTermsQi0+i].alpha = PowerTableQi0[i].alpha;
			PowerTableQi0[NumTermsQi0+i].beta = PowerTableQi0[i].beta;
			PowerTableQi0[NumTermsQi0+i].gamma = PowerTableQi0[i].gamma;
		}
		for (int i = 0; i < NumTermsQiGt0; i++) {
			PowerTableQiGt0[NumTermsQiGt0+i].ki = PowerTableQiGt0[i].ki - l;
			PowerTableQiGt0[NumTermsQiGt0+i].li = PowerTableQiGt0[i].li + l;
			PowerTableQiGt0[NumTermsQiGt0+i].mi = PowerTableQiGt0[i].mi;
			PowerTableQiGt0[NumTermsQiGt0+i].ni = PowerTableQiGt0[i].ni;
			PowerTableQiGt0[NumTermsQiGt0+i].pi = PowerTableQiGt0[i].pi;
			PowerTableQiGt0[NumTermsQiGt0+i].qi = PowerTableQiGt0[i].qi;
			PowerTableQiGt0[NumTermsQiGt0+i].alpha = PowerTableQiGt0[i].alpha;
			PowerTableQiGt0[NumTermsQiGt0+i].beta = PowerTableQiGt0[i].beta;
			PowerTableQiGt0[NumTermsQiGt0+i].gamma = PowerTableQiGt0[i].gamma;
		}
	}
	//cout << "Node " << Node << ": " << NodeStart << " " << NodeEnd << endl;
	MpiError = MPI_Barrier(MPI_COMM_WORLD);
#endif
//#ifdef USE_MPI
//	MpiError = MPI_Barrier(MPI_COMM_WORLD);
//
//	// Tell all processes what terms they should be evaluating.
//	if (Node == 0) {
//		NumTermsProc = (double)(NumShortTerms+1) / (double)TotalNodes;  //@TODO: Need the typecast?
//		for (int i = 1; i < TotalNodes; i++) {
//			NodeStart = NumTermsProc * i;
//			NodeEnd = NumTermsProc * (i+1) - 1;
//			MpiError = MPI_Send(&NodeStart, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
//			MpiError = MPI_Send(&NodeEnd, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
//		}
//		// This is the set of values for the root node to take.
//		NodeStart = 0;
//		NodeEnd = NumTermsProc * (Node+1) - 1;
//		}
//	else {
//		MpiError = MPI_Recv(&NodeStart, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);
//		MpiError = MPI_Recv(&NodeEnd, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &MpiStatus);
//	}
//	MpiError = MPI_Barrier(MPI_COMM_WORLD);
//	//@TODO: To clean this up some, we could just output this in the loop above for node 0.
//	cout << "Node " << Node << ": " << NodeStart << " " << NodeEnd << endl;
//#else
//	NumTermsProc = (double)(NumShortTerms+1);
//	NodeStart = 0;
//	NodeEnd = NumTermsProc * (Node+1) - 1;
//#endif//USE_MPI

	//TimeStart = time(NULL);
	//CalcARowAndBVector(Node, NumTerms, Omega, PowerTable, AResults, ARow, BResults, B, SLS, q, r2Cusp, r3Cusp, Alpha, Beta, Gamma, Kappa, Mu, sf);
	CalcARowAndBVector(Node, NumTermsQi0, NumTermsQiGt0, Omega, PowerTableQi0, PowerTableQiGt0, AResultsQi0, AResultsQiGt0, ARow, BResultsQi0, BResultsQiGt0, B, SLS, SLC, l, q, r2Cusp, r3Cusp, Alpha, Beta, Gamma, Kappa, Mu, Lambda1, Lambda2, Lambda3, ShPower, sf);
	//TimeEnd = time(NULL);
	//cout << "Time elapsed: " << difftime(TimeEnd, TimeStart) << endl;
	//OutFile << "Time elapsed: " << difftime(TimeEnd, TimeStart) << endl;
	

#ifdef USE_MPI
	if (Node == 0) {
		//@TODO: Temporary
		int NumTermsQi0Temp = CalcPowerTableSizeQi0(Omega, Ordering, 0, NumShortTerms);
		int NumTermsQiGt0Temp = CalcPowerTableSizeQiGt0(Omega, Ordering, 0, NumShortTerms);

		for (int i = 0; i < NumTermsQi0; i++) {
			AResultsQi0Final[i] = AResultsQi0[i];
			AResultsQi0Final[NumTermsQi0Temp+i] = AResultsQi0[NumTermsQi0+i];
			BResultsQi0Final[i] = BResultsQi0[i];
			BResultsQi0Final[NumTermsQi0Temp+i] = BResultsQi0[NumTermsQi0+i];
		}
		for (int i = 0; i < NumTermsQiGt0; i++) {
			AResultsQiGt0Final[i] = AResultsQiGt0[i];
			AResultsQiGt0Final[NumTermsQiGt0Temp+i] = AResultsQiGt0[NumTermsQiGt0+i];
			BResultsQiGt0Final[i] = BResultsQiGt0[i];
			BResultsQiGt0Final[NumTermsQiGt0Temp+i] = BResultsQiGt0[NumTermsQiGt0+i];
		}

		cout << " Node " << Node << " (" << ProcessorName << ") finished computation at " << ShowTime() << endl;
		// ResultsQi0 and ResultsQiGt0 already have process 0's results.
		//  Gather the results from the rest of the processes.
		int nQi0 = NumTermsQi0Array[0], nQiGt0 = NumTermsQiGt0Array[0];
		// IMPORTANT NOTE! i++ must be at the end, or else it increments before nQi0 and nQiGt0.
		for (int i = 1; i < TotalNodes; nQi0 += NumTermsQi0Array[i], nQiGt0 += NumTermsQiGt0Array[i], i++) {
			// Phi1 terms
			MpiError = MPI_Recv(&AResultsQi0Final[nQi0], NumTermsQi0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&BResultsQi0Final[nQi0], NumTermsQi0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&AResultsQiGt0Final[nQiGt0], NumTermsQiGt0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&BResultsQiGt0Final[nQiGt0], NumTermsQiGt0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			// Phi2 terms
			MpiError = MPI_Recv(&AResultsQi0Final[NumTermsQi0Temp+nQi0], NumTermsQi0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&BResultsQi0Final[NumTermsQi0Temp+nQi0], NumTermsQi0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&AResultsQiGt0Final[NumTermsQiGt0Temp+nQiGt0], NumTermsQiGt0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
			MpiError = MPI_Recv(&BResultsQiGt0Final[NumTermsQiGt0Temp+nQiGt0], NumTermsQiGt0Array[i], MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &MpiStatus);
		}
	}
	else {
		cout << " Node " << Node << " (" << ProcessorName << ") finished computation at " << ShowTime() << endl;
		// Phi1 terms
		MpiError = MPI_Send(&AResultsQi0[0], NumTermsQi0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&BResultsQi0[0], NumTermsQi0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&AResultsQiGt0[0], NumTermsQiGt0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&BResultsQiGt0[0], NumTermsQiGt0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		// Phi2 terms
		MpiError = MPI_Send(&AResultsQi0[NumTermsQi0], NumTermsQi0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&BResultsQi0[NumTermsQi0], NumTermsQi0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&AResultsQiGt0[NumTermsQiGt0], NumTermsQiGt0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
		MpiError = MPI_Send(&BResultsQiGt0[NumTermsQiGt0], NumTermsQiGt0, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
	}
#else
	AResultsQi0Final = AResultsQi0;
	BResultsQi0Final = BResultsQi0;
	AResultsQiGt0Final = AResultsQiGt0;
	BResultsQiGt0Final = BResultsQiGt0;
#endif

	if (Node == 0) {
		//@TODO: Put directly into A and B
		vector <double> AResults(NumShortTerms*2), BResults(NumShortTerms*2);
		CombineResults(Omega, Ordering, AResultsQi0Final, AResultsQiGt0Final, AResults, 0, NumShortTerms);
		CombineResults(Omega, Ordering, BResultsQi0Final, BResultsQiGt0Final, BResults, 0, NumShortTerms);

		for (int i = 0; i < NumShortTerms*2; i++) {
			ARow[i+1] = AResults[i];
		}
		for (int i = 0; i < NumShortTerms*2; i++) {
			B[i+1] = BResults[i];
		}

		int Multiplier;
		if (l == 0) Multiplier = 1;  // S-wave only has a single symmetry
		else Multiplier = 2;

		cout << endl << endl << "A matrix row" << endl;
		for (int i = 0; i < NumShortTerms*Multiplier+1; i++) {
			cout << i << " " << ARow[i] << endl;
		}

		cout << endl << "B vector" << endl;
		for (int i = 0; i < NumShortTerms*Multiplier+1; i++) {
			cout << i << " " << B[i] << endl;
		}
		cout << endl;

		// Construct the rest of the matrix A with the short-range - short-range terms.
		for (int i = 0; i < NumShortTerms*2; i++) {
			for (int j = 0; j < NumShortTerms*2; j++) {
				ShortTerms[i*NumShortTerms*2+j] = PhiHPhi[i][j] - 0.5*Kappa*Kappa * PhiPhi[i][j] + 1.5*PhiPhi[i][j];
			}
		}
	}

	if (Node == 0) {
		//@TODO: Move further up.
		// Output results to file
		if (Ordering == 0)
			OutFile << "Using Denton's ordering" << endl;
		else
			OutFile << "Using Peter Van Reeth's ordering" << endl;

		OutFile << "Omega: " << Omega << endl;
		OutFile << "Number of terms: " << NumShortTerms << endl;
		OutFile << "Alpha: " << Alpha << "  Beta: " << Beta << "  Gamma: " << Gamma << endl;
		OutFile << "Mu: " << Mu << endl;
		OutFile << "Shielding power: " << ShPower << endl;
		OutFile << "Kappa: " << Kappa << endl;
		OutFile << "Lambda: " << Lambda1 << " " << Lambda2 << " " << Lambda3 << " " << endl;

		OutFile << endl << "Number of quadrature points" << endl;
		OutFile << "Long-long:                     " << q.LongLong_r1 << " " << q.LongLong_r2Leg << " " << q.LongLong_r2Lag << " " << q.LongLong_r3Leg << " " << q.LongLong_r3Lag << " " << q.LongLong_r12 << " " << q.LongLong_r13 << " " << q.LongLong_phi23 << endl;
		OutFile << "Long-long 2/r23 term:          " << q.LongLongr23_r1 << " " << q.LongLongr23_r2Leg << " " << q.LongLongr23_r2Lag << " " << q.LongLongr23_r3Leg << " " << q.LongLongr23_r3Lag << " " << q.LongLongr23_phi12 << " " << q.LongLongr23_r13 << " " << q.LongLongr23_r23 << endl;
		OutFile << "Short-long with qi = 0:        " << q.ShortLong_r1 << " " << q.ShortLong_r2Leg << " " << q.ShortLong_r2Lag << " " << q.ShortLong_r3Leg << " " << q.ShortLong_r3Lag << " " << q.ShortLong_r12 << " " << q.ShortLong_r13 << " " << q.ShortLong_phi23 << endl;
		OutFile << "Short-long 2/r23 with qi = 0:  " << q.ShortLongr23_r1 << " " << q.ShortLongr23_r2Leg << " " << q.ShortLongr23_r2Lag << " " << q.ShortLongr23_r3Leg << " " << q.ShortLongr23_r3Lag << " " << q.ShortLongr23_r12 << " " << q.ShortLongr23_phi13 << " " << q.ShortLongr23_r23 << endl;
		OutFile << "Short-long (full) with qi > 0: " << q.ShortLongQiGt0_r1 << " " << q.ShortLongQiGt0_r2Leg << " " << q.ShortLongQiGt0_r2Lag << " " << q.ShortLongQiGt0_r3Leg << " " << q.ShortLongQiGt0_r3Lag << " " << q.ShortLongQiGt0_r12 << " " << q.ShortLongQiGt0_r13 << " " << q.ShortLongQiGt0_phi23 << endl;
		OutFile << endl;
		OutFile << "Cusp parameters" << endl;
		OutFile << r2Cusp << " " << r3Cusp << endl;
		OutFile << endl;

		int Multiplier;
		if (l == 0) Multiplier = 1;  // S-wave only has a single symmetry
		else Multiplier = 2;

		OutFile << "A matrix row" << endl;
		for (int i = 0; i < NumShortTerms*Multiplier+1; i++) {
			OutFile << i << " " <<  ARow[i] << endl;
		}
		OutFile << endl << "B vector" << endl;
		for (int i = 0; i < NumShortTerms*Multiplier+1; i++) {
			OutFile << i << " " << B[i] << endl;
		}

		//cout << "SLS Term: " << SLS << endl;
		//cout << "SLC Term: " << SLC << endl;
		//cout << "SLC - CLS: " << SLC - B[0] << endl << endl;
		cout << endl << "SLS Term" << endl << SLS << endl;
		cout << endl << "SLC Term" << endl << SLC << endl;
		cout << "SLC - CLS: " << SLC - B[0] << endl << endl;
		OutFile << endl << "SLS Term" << endl << SLS << endl;
		OutFile << endl << "SLC Term" << endl << SLC << endl;
		OutFile << "SLC - CLS: " << SLC - B[0] << endl << endl;

		double KohnPhase, InvKohnPhase, ComplexKohnPhase;
		KohnPhase = Kohn(NumShortTerms, ARow, B, ShortTerms, SLS);
		InvKohnPhase = InverseKohn(NumShortTerms, ARow, B, ShortTerms, SLS);
		ComplexKohnPhase = ComplexKohnT(NumShortTerms, ARow, B, ShortTerms, SLS);
		cout << "Kohn phase shift: " << KohnPhase << endl;
		cout << "Inverse Kohn phase shift: " << InvKohnPhase << endl;
		cout << "Complex Kohn phase shift: " << ComplexKohnPhase << endl << endl;
		OutFile << "Kohn phase shift: " << KohnPhase << endl;
		OutFile << "Inverse Kohn phase shift: " << InvKohnPhase << endl;
		OutFile << "Complex (T-matrix) Kohn phase shift: " << ComplexKohnPhase << endl << endl;

		double CrossSection = 4.0 * PI * sin(KohnPhase) * sin(KohnPhase);  // (2l+1) = 1 with l = 0
		cout << "Kohn partial wave cross section: " << CrossSection << endl;
		OutFile << "Kohn Partial wave cross section: " << CrossSection << endl;
		CrossSection = 4.0 * PI * sin(InvKohnPhase) * sin(InvKohnPhase);
		cout << "Inverse Kohn partial wave cross section: " << CrossSection << endl;
		OutFile << "Inverse Kohn partial wave cross section: " << CrossSection << endl;
		CrossSection = 4.0 * PI * sin(ComplexKohnPhase) * sin(ComplexKohnPhase);
		cout << "Complex (T-matrix) Kohn partial wave cross section: " << CrossSection << endl << endl;
		OutFile << "Complex (T-matrix) Kohn partial wave cross section: " << CrossSection << endl << endl;
	}


	// Cleanup
	if (Node == 0) {
		TimeEnd = time(NULL);
		cout << "Time elapsed: " << difftime(TimeEnd, TimeStart) << endl;
		OutFile << "Time elapsed: " << difftime(TimeEnd, TimeStart) << endl;
		ParameterFile.close();
		OutFile.close();
		FileShortRange.close();
		if (NumShortTerms > 0) {
			delete [] PhiHPhi[0];
			delete [] PhiHPhi;
			delete [] PhiPhi[0];
			delete [] PhiPhi;
		}
	}
	cout << endl;
	fflush(stdout);

#ifdef USE_MPI
	//MpiError = MPI_File_close(&MpiLog);
	MpiError = MPI_Finalize();
#endif

	return 0;
}
Beispiel #2
0
int main(int argc, char* argv[])
{
  MPI_Init(&argc, &argv);
  
  Int i, j;
  Int ierr = 0;
  std::stringstream ss;
  Real TGiven;
  Real* rhoi;
  Real* wdot;
  Real* molfrac;

  if(argc != 3){
    std::cerr << "USAGE: " << argv[0] << " casename Temperature(K)" << std::endl;
    return(1);
  }
  
  //setup parameter file so we can read reference states, etc.
  std::vector<Param<double>*> paramList;
  SolutionOrdering<Real> operations;
  TemporalControl<double> temporalControl;
  std::string casestring = argv[1];
  size_t pos = casestring.rfind('/');
  std::string pathname;
  if(pos != std::string::npos){
    pathname = casestring.substr(0, pos+1);
    casestring = casestring.substr(pos);
  }
  else{
    pathname = "./";
  }
  if(ReadParamFile(paramList, casestring, pathname)){
    return (-1);
  }
  if(operations.Read(casestring, pathname)){
    return (-1);
  }
  if(temporalControl.Read(casestring, pathname)){
    return (-1);
  }

  //only use the first solution space defined in param file
  Param<double> param = *paramList.front();

  //read temperature for production rates from command line
  ss << argv[2];
  ss >> TGiven;

  //read reaction file
  ChemModel<double> chem(param.casestring, param.chemDB);

  rhoi = new Real[chem.nspecies];
  wdot = new Real[chem.nspecies];
  molfrac = new Real[chem.nspecies];

  //using massfraction information available from param file if there
  //print out standard state conditions using chemistry
  if(param.molefractions.size() == chem.nspecies){
    //convert to massfractions
    double* molfrac = (double*)alloca(sizeof(double)*chem.nspecies);
    double* massfrac = (double*)alloca(sizeof(double)*chem.nspecies); 
    for(int i = 0; i < chem.nspecies; ++i){
      molfrac[i] = param.molefractions[i];
    }
    chem.MoleFractionToMassFraction(molfrac, massfrac);
    param.massfractions.resize(chem.nspecies);
    for(int i = 0; i < chem.nspecies; ++i){
      param.massfractions[i] = massfrac[i];
    }
  }
  
  if(param.massfractions.size() == chem.nspecies){
    for(i = 0; i < chem.nspecies; i++){
      std::cout << "rho[" << chem.species[i].symbol << "]: " 
		<< param.massfractions[i]*param.ref_density << " kg/m^3" << std::endl;
    }
  }
  else{
    std::cerr << "Number of species defined in param file does not match chem model" << std::endl;
    return(-1);
  }

  //compute rho and R, store massfractions
  double rho = 0.0;
  double R = 0.0;
  double X[chem.nspecies]; //massfraction
  if(param.massfractions.size() == chem.nspecies){
    for(i = 0; i < chem.nspecies; i++){
      X[i] = param.massfractions[i];
      rhoi[i] = param.massfractions[i]*param.ref_density;
      rho += rhoi[i];
      R += chem.species[i].R*(rhoi[i]);
    }
  }
  //R is dimensional after this
  R /= rho;
  double P = chem.GetP(rhoi, TGiven);
  double gamma = 0.0;
  double cv = 0.0;
  double cp = 0.0;
  double hi[chem.nspecies];
  if(param.massfractions.size() != chem.nspecies){
    std::cerr << "Number of species defined in param file does not match chem model" << std::endl;
    return(-1);
  }
  int Tlevels = (int)3500/100.0;
  std::cout << std::endl;
  std::cout << "Temp(K)" << "\t" << std::setw(10) << "Cv(J/kg.K)"
	    << "\t" << std::setw(8) << "Cp(J/kg.K)"
	    << "\t" << std::setw(8) << "Cp/R"
	    << "\t" << std::setw(8) << "H(J/kg)"
	    << "\t" << std::setw(8) << "h/RT"
	    << "\t" << std::setw(8) << "mu(Pa.s)"
	    << "\t" << std::setw(8) << "k(W/m.K)" << std::endl;
  std::cout << "----------------------------------------------------------------------------------------------------------------------" << std::endl;
  for(j = 0; j < Tlevels; j++){
    double Ti = (double)(j*100.0 + 100.0);
    double cp = chem.GetCp(rhoi, Ti);
    double cv = chem.GetCv(rhoi, Ti);
    double h = chem.GetSpecificEnthalpy(X, Ti, hi);
    double mu = chem.GetViscosity(rhoi, Ti);
    double k = chem.GetThermalConductivity(rhoi, Ti);
    std::cout << Ti
	      << "\t" << std::setw(10) << cv
	      << "\t" << std::setw(10) << cp
	      << "\t" << std::setw(10) << cp/R
	      << "\t" << std::setw(10) << h
	      << "\t" << std::setw(10) << h/R/Ti
	      << "\t" << std::setw(10) << mu
	      << "\t" << std::setw(10) << k << std::endl;
  }
  std::cout << std::endl;
  cv = chem.GetCv(rhoi, TGiven);
  cp = chem.GetCp(rhoi, TGiven);
  gamma = cp/cv;
  
  //compute mol fractions and MW_mix
  double MWmix = 0.0;
  std::cout << "\nMole fractions" << std::endl;
  std::cout << "========================= " << std::endl;
  double massfrac[chem.nspecies];
  for(int i = 0; i < chem.nspecies; ++i){
    massfrac[i] = param.massfractions[i];
  }
  chem.MassFractionToMoleFraction(massfrac, molfrac);
  for(int i = 0; i < chem.nspecies; ++i){
    MWmix += molfrac[i] * chem.species[i].MW;
    std::cout << "xi[" << chem.species[i].symbol << "]: " << molfrac[i] << std::endl;
  }
  std::cout << "\nMass fractions" << std::endl;
  std::cout << "========================= " << std::endl;
  for(int i = 0; i < chem.nspecies; ++i){
    std::cout << "Yi[" << chem.species[i].symbol << "]: " << param.massfractions[i] << std::endl;
  }
  std::cout << std::endl;

  std::cout << "Mixture properties at " << TGiven << " (K)" << std::endl;
  std::cout << "=======================================" << std::endl;

  std::cout << "rho: " << rho << " kg/m^3" << std::endl;
  std::cout << "Rmix: " << R << " J/kg.K" << std::endl;
  std::cout << "Static pressure (EOS only): " << P << " Pa" << std::endl;
  std::cout << "cvmix: " << cv << " (J/kg.K)" << std::endl;
  std::cout << "cpmix: " << cp << " (J/kg.K)" << std::endl;
  std::cout << "mwmix: " << MWmix << " (kg/mol)" << std::endl;
  std::cout << "gammamix: " << gamma << std::endl;
  std::cout << "Thermal conductivity: " << chem.GetThermalConductivity(rhoi, TGiven) << " (W/m.K)" << std::endl;
  std::cout << "Viscosity: " << chem.GetThermalConductivity(rhoi, TGiven) << " (Pa.s)" << std::endl;
  double c = sqrt(gamma*R*TGiven);
  std::cout << "c (speed of sound): " << c << " m/s" << std::endl;
  double u = param.flowdir[0]*param.GetVelocity(1)*param.ref_velocity;
  double v = param.flowdir[1]*param.GetVelocity(1)*param.ref_velocity;
  double w = param.flowdir[2]*param.GetVelocity(1)*param.ref_velocity;
  double v2 = u*u + v*v + w*w;
  std::cout << "U: " << u  << " m/s" << std::endl;
  std::cout << "V: " << v  << " m/s" << std::endl;
  std::cout << "W: " << w  << " m/s" << std::endl;
  std::cout << "Mach: " << sqrt(v2/(c*c)) << std::endl;
  double Ht = rho*chem.GetSpecificEnthalpy(X, TGiven, hi) + 0.5*rho*v2;
  double Et = rho*chem.GetSpecificEnthalpy(X, TGiven, hi) - P + 0.5*rho*v2;
  std::cout << "Total enthalpy: " << Ht/1000.0 << " (kJ)" << std::endl;
  std::cout << "Total energy: " << Et/1000.0 <<  " (kJ)" << std::endl;
  std::cout << "Total internal energy: " << (Et - 0.5*rho*v2)/1000.0 <<  " (kJ)" << std::endl;
  
  std::cout << "Total pressure (gamma-1.0 formula): " << ((gamma - 1.0)*(Et - 0.5*rho*v2)/param.ref_enthalpy)*
    param.ref_pressure << " Pa" << std::endl;
  std::cout << "Total temperature (gamma-1.0 formula): " << TGiven*(1.0  + (gamma-1.0)/2.0*(v2/(c*c))) << " (K) " << std::endl;
    
  std::cout << "\nAt given temperature of " << TGiven << "K production rates are: " << std::endl;
  std::cout << "===================================================" << std::endl;
  chem.GetMassProductionRates(rhoi, TGiven, wdot);
  for(i = 0; i < chem.nspecies; i++){
    std::cout << chem.species[i].symbol << ": " << wdot[i] << " kg/(m^3 s)" << std::endl;
  }
  
  Real sum = 0.0;
  for(i = 0; i < chem.nspecies; i++){
    sum += wdot[i];
  }
  std::cout << "Mass blanance: " << sum << " kg/(m^3 s)" << std::endl;

  std::cout << "\nDerivatives at given temp: " << TGiven << std::endl;
  std::cout << "===================================================" << std::endl;
  double* dEtdRhoi = new double[chem.nspecies];
  double Pt = chem.GetP(rhoi, TGiven);
  double dEtdP = chem.dEtdP_dEtdRhoi(rhoi, TGiven, Pt, v2, dEtdRhoi);
  std::cout << "dEtdP: " << dEtdP << std::endl;
  for(Int i = 0; i < chem.nspecies; i++){
    std::cout << "dEtdrho[" << i << "]: " << dEtdRhoi[i] << std::endl;
  }

#if 0
  //temporal loop to compute change in makeup over time
  double dt = 0.0001;
  double volume = 1.0; //m^3
  Real* source = new Real[chem.nspecies];
  Real* Y = new Real[chem.nspecies];
  P = Pt;
  Real tol = 1.0e-12;
  Real T = TGiven;
  for(i = 0; i < 20; ++i){
    std::cout << dt*i << " ----------------------------------------------" << std::endl;
    std::cout << "Temp: " << T << std::endl;
    chem.GetMassProductionRates(rhoi, T, wdot);
    for(int is = 0; is < chem.nspecies; ++is){
      source[is] = wdot[is]*volume*dt;
      std::cout << "s: " << source[is] << std::endl;
    }

    //update the masses/densities given the source term (production/destruction)
    rho = 0.0;
    R = 0.0;
    for(int is = 0; is < chem.nspecies; ++is){
      Real mass = rhoi[is]*volume + source[is];
      rhoi[is] = mass/volume;
      rho += rhoi[is];
      R += rhoi[is]*chem.species[is].R;
    }
    std::cout << "Rho: " << rho << std::endl;
    // R is dimensional after this
    R /= rho;
    for(int is = 0; is < chem.nspecies; ++is){
      Y[is] = rhoi[is]/rho;
      std::cout << "y: " << Y[is] << std::endl;
    }
    
    int j = 0;
    Int maxit = 30;
    Real dT = 0.0;
    //todo: check if this is correct
    Real res = Et - 0.5*rho*v2;
    for(j = 0; j < maxit; j++){
      Real Tp = T + 1.0e-8;
      Real H = rho*(chem.GetSpecificEnthalpy(Y, T, hi));
      Real Hp = rho*(chem.GetSpecificEnthalpy(Y, Tp, hi));
      Real P = chem.eos->GetP(R, rho, T);
      Real Pp = chem.eos->GetP(R, rho, Tp);
      Real E = H - P;
      Real Ep = Hp - Pp;
      Real zpoint = res - E;
      Real zpointp = res - Ep;
      Real dzdT = (zpointp - zpoint)/(Tp - T);
      dT = -zpoint/dzdT;
      T += dT;
      if (real(CAbs(dT)) < real(tol)) break;
    }

    if(j == maxit){
      std::cerr << "WARNING: Newton iteration did not converge on a temperature in ConservativeToNative()" 
		<< std::endl;
      std::cerr << "Last dT = " << dT << std::endl;
    }
    
  }
  delete [] source;
  delete [] Y;
#endif
  
  delete [] dEtdRhoi;
  delete [] rhoi;
  delete [] wdot;
  delete [] molfrac;

  return(ierr);
}