using System;
using System.Reflection;
using DataFitXD2;

namespace DataFitX2_CSharp_dot_NET
{
	
	class Class1
	{
		[STAThread]
		static void Main(string[] args)
		{	
			String DecimalSep = ".";
			String DateSep = "/";

			try 
			{				
				// 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".
				DataCollection dfxData = new DataCollection();
				dfxData.ImportNamedSeriesFromFile("thurber.dat", DelimiterTypeEnum.dfxDelimiterTab, 
                                                  DecimalSep, DateSep, Type.Missing);

				// Set the RegressionKey properties for the DataCollection according to the
				// above description.
				dfxData["Density"].RegressionKey = "X";							
				dfxData["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.
				ModelDefinition dfxDefinition = new 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
				NonlinearRegression dfxModel = new 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, InputLocaleEnum.dfxLocaleEnglish);			
    
				// Define the intial estimates for the model since this is a
				// user-defined model. There are seven parameters, B1 through B7.			
				dfxModel.RegressionParameters["B1"].InitialEstimate = 1000;
				dfxModel.RegressionParameters["B2"].InitialEstimate = 1000;
				dfxModel.RegressionParameters["B3"].InitialEstimate = 400;
				dfxModel.RegressionParameters["B4"].InitialEstimate = 40;
				dfxModel.RegressionParameters["B5"].InitialEstimate = 0.7;
				dfxModel.RegressionParameters["B6"].InitialEstimate = 0.3;
				dfxModel.RegressionParameters["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) 
				{
					Console.WriteLine("Results for model: ");
					Console.WriteLine("F1 = " + dfxModel.ModelDefinition.F1);
					Console.WriteLine("F2 = " + dfxModel.ModelDefinition.F2);
					Console.WriteLine("Y = " + dfxModel.ModelDefinition.Y);
					Console.WriteLine("Description: " + dfxModel.ModelDefinition.Description);

					// Print information about the data
					Console.WriteLine("Data set: Thurber.dat");
					Console.WriteLine("Independent Variable (X): " + dfxModel.ResultTables[1].Name);
					Console.WriteLine("Dependent Variable (Y): " + dfxModel.ResultTables[2].Name);
					Console.WriteLine("Number of Observations = " + dfxModel.NumObservations);
					Console.WriteLine("XMin = " + dfxModel.ResultTables[1].Minimum);
					Console.WriteLine("XMax = " + dfxModel.ResultTables[1].Maximum);
					Console.WriteLine("YMin = " + dfxModel.ResultTables[2].Minimum);
					Console.WriteLine("YMax = " + dfxModel.ResultTables[2].Maximum);
					Console.WriteLine();

					// Print the parameter names, values and standard errors
					Console.WriteLine("Parameter Results:");
					foreach (RegressionParameter parameter in dfxModel.RegressionParameters) 
					{
						Console.WriteLine(parameter.Name + " = " + parameter.Value);
						Console.WriteLine("Standard Error = " + parameter.StandardError);
						Console.WriteLine();
					}

					// Print goodness of fit information
					Console.WriteLine("Number of Nonlinear Iterations = " + dfxModel.NumIterations);
					Console.WriteLine("Residual Standard Error = " + dfxModel.StandardError);
					Console.WriteLine("R2 Value = " + dfxModel.R2);
					Console.WriteLine("Regression Sum of Squares = " + dfxModel.SSR);
					Console.WriteLine("Residual Sum of Squares = " + dfxModel.SSE);
					Console.WriteLine();

					// Other sample output
            
					// Single Predicted value
					Console.WriteLine("Value of Y at X = 0.79: " + dfxModel.PredictValue(0.79));

					// Value of X at specified Y (Root)
					Console.WriteLine("Value(s) of X at Y = 1408.1046: ");
					Array Roots = dfxModel.CalculateRoots(1408.1046, -5.0, 2.0, 100);
					for ( int i = Roots.GetLowerBound(0); i <= Roots.GetUpperBound(0); i++ )
					{
						Console.WriteLine("Root at X = " + Roots.GetValue(i));           
					}

					// Derivative of Y at X = 2.1
					Console.WriteLine("Derivative at X = 2.1: " + dfxModel.CalculateDerivative(2.1));
            
					//Integration from X = -2.1 to 2.1
					Console.WriteLine("Integral from -2.1 to 2.1: " + dfxModel.CalculateIntegral(-2.1, 2.1)); 
				
				}
				else 
				{
					// Solution Failed
					Console.WriteLine("Solution Failed. See log.txt");
					dfxModel.SaveLog("log.txt", false);
				}
			}

			catch (Exception e)
			{
				Console.WriteLine("Exception in Main: " + e.Message + "\n\n");
			}

		}
	}
}
