#include <stdio.h>
#include <iostream.h>
#include <fstream.h>

//*****************************************************************
//
// This is an example of using DataFitX COM component (oedfx20d.dll) 
// from Microsoft Visual C++ version 6.0 in a Win32 console
// application. 
//
//*****************************************************************


// The #import directive is used to incorporate information from a
// type library. The content of the type library is converted into
// C++ classes, describing the COM interfaces.
//
//
// A _com_ptr_t object encapsulates a COM interface pointer and is
// called a smart pointer. This template class manages resource
// allocation and deallocation, via function calls to the IUnknown
// member functions: QueryInterface, AddRef, and Release.
//
// A smart pointer is usually referenced by the typedef definition
// provided by the _COM_SMARTPTR_TYPEDEF macro. This macro takes
// an interface name and the IID, and declares a specialization
// of _com_ptr_t with the name of the interface plus a suffix of Ptr.
//
// The following path must be set to the location of the curve 
// fitting library oedfx20d.dll. Make sure that you specify the
// exact path. This method can be used in Win32, ATL, or MFC projects.

#import "c:\oakdale engineering\datafitx activex dll\develope\source\oedfx20d.dll"  no_namespace

void main()
{

	const _bstr_t DecimalSep = ".";
	const _bstr_t DateSep = "/";
	long index;
	long aiIndex[1];
	long ArrayBound;
	double Result;
	SAFEARRAY * Roots;
	HRESULT hres;
	_bstr_t ErrorDesc;

	try {
		// Initialize COM
		CoInitialize(NULL);

		// Create the DataCollection object and import the tabbed delimited data
		// file thurber.dat. The file contains 2 columns of named data labeled
		// Density and Electron Mobility (the first non-blank line in the file
		// contains the series names). The first column is the independent
		// variable X (Density), the second column is the dependent
		// variable Y (Electron Mobility). This will add 2 DataSeries objects to
		// the DataCollection, one named "Density" the other named "Electron Mobility".
		_DataCollectionPtr dfxData(__uuidof(DataCollection));
		dfxData->ImportNamedSeriesFromFile("thurber.dat", dfxDelimiterTab, DecimalSep, DateSep);

		// Set the RegressionKey properties for the DataCollection according to the
		// above description.
        dfxData->Item["Density"]->RegressionKey = "X";
        dfxData->Item["Electron Mobility"]->RegressionKey = "Y";		

		// The model being solved is:
		// Y = (B1+B2*x+B3*x^2+B4*x^3) / (1+B5*x+B6*x^2+B7*x^3)
		// where B1 through B7 are the fitting parameters, and X
		// is the independent variable "Density".
		// Create the model definition object so that we may define
		// a multi-line user-defined model.
        _ModelDefinitionPtr dfxDefinition(__uuidof(ModelDefinition));        
        dfxDefinition->Description = "Semiconductor electron mobility modeling";
        dfxDefinition->F1 = "(B1 + B2 * x + B3 * x ^ 2 + B4 * x ^ 3)";
        dfxDefinition->F2 = "(1 + B5 * x + B6 * x ^ 2 + B7 * x ^ 3)";
        dfxDefinition->Y = "F1/F2";

		// Create an instance of the NonlinearRegression object
		_NonlinearRegressionPtr dfxModel(__uuidof(NonlinearRegression));

		// Define the multi-line user-defined model
        // according to the above definition in dfxDefinition.
        // Since we are using a ModelDefinition object to define
        // the model, use the DefineUserModelSub method.
        dfxModel->DefineUserModelSub(dfxDefinition, dfxLocaleEnglish);

		// Define the intial estimates for the model since this is a
        // user-defined model. There are seven parameters, B1 through B7.
        dfxModel->RegressionParameters->Item["B1"]->InitialEstimate = 1000.0;
        dfxModel->RegressionParameters->Item["B2"]->InitialEstimate = 1000.0;
        dfxModel->RegressionParameters->Item["B3"]->InitialEstimate = 400.0;
        dfxModel->RegressionParameters->Item["B4"]->InitialEstimate = 40.0;
        dfxModel->RegressionParameters->Item["B5"]->InitialEstimate = 0.7;
        dfxModel->RegressionParameters->Item["B6"]->InitialEstimate = 0.3;
        dfxModel->RegressionParameters->Item["B7"]->InitialEstimate = 0.03;

		// Set the regression solution options
        dfxModel->MaxIterations = 100;
        dfxModel->MaxUnchangedIterations = 10;
        dfxModel->RegressionTolerance = 0.0000000001;
    
        // Fit the model to the DataCollection dfxData
        dfxModel->FitCollection(dfxData);

		// If the model solved successfully, display some sample results. Otherwise,
        // display the solution log information to diagnose why it may have failed.
		if (dfxModel->IsSolved) {
			ofstream ofs( "results.dat" );
			if ( ofs ) {
				ofs.setf(ios::fixed);				
				ofs << "Results for model: " << endl;
				ofs << "F1 = " << dfxModel->ModelDefinition->F1 << endl;
				ofs << "F2 = " << dfxModel->ModelDefinition->F2 << endl;
				ofs << "Y = " << dfxModel->ModelDefinition->Y << endl;
				ofs << "Description: " << dfxModel->ModelDefinition->Description << endl;
				ofs << "Data set: Thurber.dat" << endl;
				ofs << "Independent Variable (X): Density" << endl;
				ofs << "Dependent Variable (Y): Electron Mobility" << endl;
				ofs << "Number of Observations = " << dfxModel->NumObservations << endl;
				ofs << "XMin = " << dfxModel->ResultTables->Item["Density"]->Minimum << endl;
				ofs << "XMax = " << dfxModel->ResultTables->Item["Density"]->Maximum << endl;
				ofs << "YMin = " << dfxModel->ResultTables->Item["Electron Mobility"]->Minimum << endl;
				ofs << "YMax = " << dfxModel->ResultTables->Item["Electron Mobility"]->Maximum << endl << endl;

				// Print the parameter names, values and standard errors
				ofs.precision(12);
				ofs << "Parameter Results:" << endl;
				for (index = 1;index <= dfxModel->RegressionParameters->Count;index++) {
					ofs << dfxModel->RegressionParameters->Item[index]->Name 
						<< " = " 
						<< dfxModel->RegressionParameters->Item[index]->Value 
						<< ", Standard Error = " 
						<< dfxModel->RegressionParameters->Item[index]->StandardError
						<< endl;					
				}
				ofs << endl;

				// Print goodness of fit information
				ofs << "Number of Nonlinear Iterations = " << dfxModel->NumIterations << endl;
				ofs << "Residual Standard Error = " << dfxModel->StandardError << endl;
				ofs << "R2 Value = " << dfxModel->R2 << endl;
				ofs << "Regression Sum of Squares = " << dfxModel->SSR << endl;
				ofs << "Residual Sum of Squares = " << dfxModel->SSE << endl;
				ofs << endl;

				// Other sample output

				// Single Predicted value
                ofs << "Value of Y at X = 0.79: " << dfxModel->PredictValue(0.79) << endl;

				// Value of X at specified Y (Root)
				ofs << "Value(s) of X at Y = 1408.1046:" << endl;
				Roots = dfxModel->CalculateRoots(1408.1046, -5.0, 2.0, 100);
				if (hres = SafeArrayGetUBound(Roots, 1, &ArrayBound)) throw hres;
				for (index = 0; index <= ArrayBound; index++) {
					aiIndex[0] = index;
					if (hres = SafeArrayGetElement(Roots, aiIndex, &Result)) throw hres;
					ofs << "Root at X = " << Result << endl;
				}

				// Derivative of Y at X = 2.1
                ofs << "Derivative at X = 2.1: " << dfxModel->CalculateDerivative(2.1) << endl;

				// Integration from X = -2.1 to 2.1
                ofs << "Integral from -2.1 to 2.1: " << dfxModel->CalculateIntegral(-2.1, 2.1) << endl;

				ofs.close();

				printf("Solution successful - see results.dat\n\n");

			} 
			else {
		        
				printf("Unable to open file results.dat for writing\n\n");
			}

		}
		else {

			// Solution failed, dump the log file
			dfxModel->SaveLog("log.txt", false);
			printf("Solution failed - see log.txt\n\n");

		}		
	}

	catch(_com_error &e) {
       ErrorDesc = e.Source() + " Error: " +  e.Description();
	   printf(ErrorDesc + "\n\n");
    }		

	// Unitialize COM
	CoUninitialize();

}



