#pragma once
#include "lbm.h"

template< typename MM>
struct D1Q3 : LBM<MM>
{
	static constexpr const char* id = "d1q3";
	void setC(matrix &C)
	{
		C = matrix(1, 3);
		int maxima_matrix[1][3] = {
			{0,	1,	-1}
		};
		for (int i=0;i<1;i++)
		for (int j=0;j<3;j++)
			C(i,j) = (ex)(maxima_matrix[i][j]);
	}
	D1Q3() : LBM<MM>(3) {}
};

struct D1Q3_M1
{
	static constexpr const char* id = "M1";
	static void setM(matrix &M, matrix &C)
	{
		const int Q=3,D=1;
		M = matrix(Q, Q);
		for (int j=0;j<Q;j++)
		{
			M(0,j) = (ex)1;
			for (int d=0;d<D;d++) M(d+1,j) = C(d,j);
			M(2,j) = pow(C(0,j), 2);
		}
	}
	static ex get_moments_eq(int q, FUN& fun, ex sym_cs, matrix &C)
	{
		if (q==0) return fun.rho;
		if (q==1) return fun.rho*fun.vel[0];
		if (q==2) return fun.rho*(fun.vel[0]*fun.vel[0] + sym_cs*sym_cs);
		return 0;
	}
};

template< typename MM>
struct D1Q3_SRT : D1Q3<MM>
{
	static constexpr const char* id_col = "srt";
	using LBM<MM>::Q;

	virtual void setA(matrix &A, ex& u, ex&v, ex&w)
	{
		A = matrix(Q, Q);
		for (int i=0;i<Q;i++)
		for (int j=0;j<Q;j++)
			A(i,j) = (i==j) ? (ex)LBM<MM>::sym_o : (ex)0;
	}

};

template< typename MM>
struct D1Q3_MRT1 : D1Q3<MM>
{
	static constexpr const char* id_col = "mrt1";
	virtual void setM(matrix &M, matrix &C)
	{
		D1Q3_M1::setM(M,C);
	}
	virtual void setA(matrix &A, ex& u, ex&v, ex&w)
	{
		matrix S,M;
		LBM<MM>::setS(S);
	        LBM<MM>::setM(M);
	        matrix Mi = inverse(M);
	        A = Mi.mul(S).mul(M);
	}
};

template< typename MM>
struct D1Q3_CLBM1 : D1Q3_MRT1<MM>
{
	static constexpr const char* id_col = "clbm1";
	virtual void setA(matrix &A, ex& u, ex&v, ex&w)
	{
		matrix S,K;
		LBM<MM>::setS(S);
		LBM<MM>::setK(K, u, v, w);
		matrix Ki = inverse(K);
		A = Ki.mul(S).mul(K);
	}
};
