/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v2012                                 |
|   \\  /    A nd           | Website:  www.openfoam.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    location    "system";
    object      controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

application     simpleFoam;

startFrom       latestTime;

startTime       0;

stopAt          endTime;

endTime         1e5;

deltaT          1;

writeControl    timeStep;

writeInterval   1e4;

purgeWrite      0;

writeFormat     ascii;

writePrecision  12;

writeCompression off;

timeFormat      general;

timePrecision   8;

runTimeModifiable true;

functions                              
{                                     
	errorNorm_U                           
	{                                  
		type coded;                       
		libs (utilityFunctionObjects);    
		writeControl writeTime;           
                                      
		name analyticalSolution_U;          
                                      
		codeWrite                         
		#{                               
			const volVectorField& U_find = mesh().lookupObject<volVectorField>("U"); 

			const volVectorField& C = mesh().C(); 

			const surfaceVectorField& Cf = mesh().Cf(); 

			const scalarField& V = mesh().V();   

			volVectorField MMS_diff_U                     
			(                                
				IOobject                       
				(                              
					"MMS_diff_U",                     
					mesh().time().timeName(),    
					mesh(),                      
					IOobject::NO_READ,           
					IOobject::AUTO_WRITE         
				),                             
				mesh(),                         
				dimensionedVector ("MMS_diff_U_", dimless, vector(0, 0, 0) ) 
			);                               

                                   
			forAll(MMS_diff_U, cellI)          
			{                               
				// Gets the x component of the current cell 
				const scalar x = C[cellI].x(); 

				//Gets the y component of the current cell 
				const scalar y = C[cellI].y(); 
                                     
				const scalar tmp0 = 2*M_PI*y; 
				const scalar tmp1 = 2.5 - Foam::sqrt(6.25 + 4*Foam::pow(M_PI, 2)); 
				const scalar tmp2 = Foam::exp(tmp1*x); 
				const scalar solution_1 = -tmp2*Foam::cos(tmp0) + 1; 
				const scalar solution_2 = (1.0/2.0)*tmp1*tmp2*Foam::sin(tmp0)/M_PI; 
				const scalar solution_3 = 0; 
                                    
				const vector solution (solution_1, solution_2, solution_3); 
                                    
				MMS_diff_U[cellI] = cmptMag(solution - U_find[cellI]); 
			}                               

			forAll(MMS_diff_U.boundaryField(), patchI)      
			{                               
				forAll(MMS_diff_U.boundaryField()[patchI], faceI)      
				{                             
					// Gets the x component of the current cell 
					const scalar x = Cf.boundaryField()[patchI][faceI].x(); 

					//Gets the y component of the current cell 
					const scalar y = Cf.boundaryField()[patchI][faceI].y(); 
                                     
					const scalar tmp0 = 2*M_PI*y; 
					const scalar tmp1 = 2.5 - Foam::sqrt(6.25 + 4*Foam::pow(M_PI, 2)); 
					const scalar tmp2 = Foam::exp(tmp1*x); 
					const scalar solution_1 = -tmp2*Foam::cos(tmp0) + 1; 
					const scalar solution_2 = (1.0/2.0)*tmp1*tmp2*Foam::sin(tmp0)/M_PI; 
					const scalar solution_3 = 0; 
	                                  
					const vector solution (solution_1, solution_2, solution_3); 
                                  
					MMS_diff_U.boundaryFieldRef()[patchI][faceI] = cmptMag(solution - U_find.boundaryField()[patchI][faceI]); 
				}                             
			}                               

			Info << "For the 1st component of the vector"                               << endl;     
			Info << "L2 norm is: "    << sqrt( gSum( MMS_diff_U.component(0)*MMS_diff_U.component(0)*V)/gSum(V) ) << endl;      


			Info << "For the 2nd component of the vector"                            << endl;        
			Info << "L2 norm is: "    << sqrt( gSum( MMS_diff_U.component(1)*MMS_diff_U.component(1)*V)/gSum(V) ) << endl;         


			Info << "For the 3rd component of the vector"                            << endl;     
			Info << "L2 norm is: "    << sqrt( gSum( MMS_diff_U.component(2)*MMS_diff_U.component(2)*V)/gSum(V) ) << endl;     
                              
			MMS_diff_U.write();                
		#};                               
	}

	errorNorm_p                           
	{                                  
		type coded;                       
		libs (utilityFunctionObjects);    
		writeControl writeTime;           
                                      
		name analyticalSolution_p;          
                                      
		codeWrite                         
		#{                               
			const volScalarField& p_find = mesh().lookupObject<volScalarField>("p"); 

			const volVectorField& C = mesh().C(); 

			const surfaceVectorField& Cf = mesh().Cf(); 

			const scalarField& V = mesh().V();   

			volScalarField MMS_diff_p                     
			(                                
				IOobject                       
				(                              
					"MMS_diff_p",                
					mesh().time().timeName(),    
					mesh(),                      
					IOobject::NO_READ,           
					IOobject::AUTO_WRITE         
				),                             
				mesh(),                         
				dimensionedScalar ("MMS_diff_p_", dimless, 0.0) 
			);                               

                                    

			forAll(MMS_diff_p, cellI)          
			{                               
				// Gets the x component of the current cell 
				const scalar x = C[cellI].x(); 
                                    
				const scalar solution = 0.5*(1 - Foam::exp(x*(5.0 - 2*Foam::sqrt(6.25 + 4*Foam::pow(M_PI, 2))))); 
                                    
				                                    
				MMS_diff_p[cellI] = mag(solution - p_find[cellI]); 
			}                               

			forAll(MMS_diff_p.boundaryField(), patchI)      
			{                               
				forAll(MMS_diff_p.boundaryField()[patchI], faceI)      
				{                             
					// Gets the x component of the current cell 
					const scalar x = Cf.boundaryField()[patchI][faceI].x(); 
                                    
					const scalar solution = 0.5*(1 - Foam::exp(x*(5.0 - 2*Foam::sqrt(6.25 + 4*Foam::pow(M_PI, 2))))); 
                                  
					                                  
					MMS_diff_p.boundaryFieldRef()[patchI][faceI] = mag(solution - p_find.boundaryField()[patchI][faceI]); 
				}                             
			}                                

			Info << "L2 norm for P is: "    << sqrt( gSum(MMS_diff_p*MMS_diff_p*V)/gSum(V) )    << endl;     

                              
			MMS_diff_p.write();                
		#};                               
	}  


}