// Lattice Boltzmann Method Analysis Tool
// https://mmg-gitlab.fjfi.cvut.cz/gitlab/lbm/lbmat

#pragma once

#include "base.h"
#include "lbm.h"
#include "tpde.h"

template< typename LBM_TYPE >
struct CORE : BASE
{
	using LBM=LBM_TYPE;
	LBM lbm;

	const int MAXO=5;	// maximal time order to deal with, increase this if you need more than that
	int ORDER=4;		// Taylor order
	int MFCO=4;		// maximal factors common order for TPDE 
	int verbosity=0;
	// link to lbm
	int Q=0, D=0;
	bool use_symbolic_coefs=!false; // use symbolic coefficients for abs_rhs to save memory

	FUN fun;

	int dump_lst_count=0;
	int subs_lst_level=0;

	// virtualize for non-matrix LBMs!!! (such as CuLBM...)
	virtual void assemble_pdes(TPDE *pde);

	bool find_lowest_time_derivative(TPDE &expression, int basindex, int order, int& kt, int& kx, int& ky, int&kz);

	void subs_time_derivatives_up_to_order(TPDE &expr, int basindex, TPDE *ders, int max_order);
	void eliminate_all_spatial_orders_for_given_time_order(int basindex, int time_order, TPDE *ders);
	void eliminate_all_spatial_orders_for_given_time_order(TPDE &target, int basindex, int time_order, TPDE &source);
	void replace_time_derivative(TPDE &target, int bj, int time_order, TPDE &derivative);

	void eliminate_higher_raw_moments(vct& bas, TPDE *pde, TPDE*abs_rhs, int offset);

	// Algorithm 1
	void gauss_eliminate_derivatives_on_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);
	void gauss_eliminate_derivatives_below_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);
	void gauss_eliminate_derivatives_above_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);
	void gauss_eliminate_coefs_on_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);
	void gauss_eliminate_coefs_below_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);
	void gauss_eliminate_coefs_above_diagonal(int bi, vct& bas, TPDE*abs_rhs, int index_offset);

	// Algorithm 2
	void compute_NSE();
	void compute_ADE();

	void compute_all();

	CORE();
};

#include "core.hpp"
