# Compile PYLOM
#   Compile with g++ or Intel C++ Compiler
#   Compile with the most aggressive optimization setting (O3)
#   Use the most pedantic compiler settings: must compile with no warnings at all
#
# The user may override any desired internal variable by redefining it via command-line:
#   make CXX=g++ [...]
#   make OPTL=-O2 [...]
#   make FLAGS="-Wall -g" [...]
#
# Arnau Miro 2021

# Include user-defined build configuration file
include options.cfg

# Compilers
#
# Automatically detect if the intel compilers are installed and use
# them, otherwise default to the GNU compilers
ifeq (,$(shell which mpiicc))
	# C Compiler
	CC  = mpicc
	# C++ Compiler
	CXX = mpicxx
	# Fortran Compiler
	FC  = mpif90
else
	# C Compiler
	CC  = mpiicc
	# C++ Compiler
	CXX = mpiicpc
	# Fortran Compiler
	FC  = mpiifort
endif
# Force use GCC compilers
ifeq ($(USE_GCC),ON)
	# Forcing the use of GCC
	# C Compiler
	CC  = mpicc
	# C++ Compiler
	CXX = mpicxx
	# Fortran Compiler
	FC  = mpif90
endif
# Force use NVHPC compilers
ifeq ($(USE_NVHPC),ON)
	# Forcing the use of GCC
	# C Compiler
	CC  = mpicc
	# C++ Compiler
	CXX = mpicxx
	# Fortran Compiler
	FC  = mpif90
endif


# Compiler flags
#
CFLAGS   += -fPIC
CXXFLAGS += -fPIC
FFLAGS   += -fPIC
ifeq ($(CC),mpicc)
	# Using GCC as a compiler
	ifeq ($(USE_GCC),ON)
		ifeq ($(DEBUGGING),ON)
			# Debugging flags
			CFLAGS   += -O0 -g -rdynamic
			CXXFLAGS += -O0 -g -rdynamic
			FFLAGS   += -O0 -g -rdynamic
		else
			CFLAGS   += -O$(OPTL) -ffast-math
			CXXFLAGS += -O$(OPTL) -ffast-math
			FFLAGS   += -O$(OPTL) -ffast-math
		endif
		# Vectorization flags
		ifeq ($(VECTORIZATION),ON)
			CFLAGS   += -march=native -ftree-vectorize
			CXXFLAGS += -march=native -ftree-vectorize
			FFLAGS   += -march=native -ftree-vectorize
		endif
		# OpenMP flag
		ifeq ($(OPENMP_PARALL),ON)
			CFLAGS   += -fopenmp -DUSE_OMP
			CXXFLAGS += -fopenmp -DUSE_OMP
		endif		
	endif		
	# NVHPC specific flags
	ifeq ($(USE_NVHPC),ON)
		ifeq ($(DEBUGGING),ON)
			# Debugging flags
			CFLAGS   += -O0 -g
			CXXFLAGS += -O0 -g
			FFLAGS   += -O0 -g
		else
			CFLAGS   += -O$(OPTL)
			CXXFLAGS += -O$(OPTL)
			FFLAGS   += -O$(OPTL)
		endif
		# Vectorization flags
		ifeq ($(VECTORIZATION),ON)
			CFLAGS   += -tp=$(TUNE) -fast
			CXXFLAGS += -tp=$(TUNE) -fast
			FFLAGS   += -tp=$(TUNE) -fast
		endif
		# OpenMP flag
		ifeq ($(OPENMP_PARALL),ON)
			CFLAGS   += -mp -DUSE_OMP
			CXXFLAGS += -mp -DUSE_OMP
		endif
	endif
else
	# Using INTEL as a compiler
	ifeq ($(DEBUGGING),ON)
		# Debugging flags
		CFLAGS   += -O0 -g -traceback
		CXXFLAGS += -O0 -g -traceback
		FFLAGS   += -O0 -g -traceback
	else
		CFLAGS   += -O$(OPTL)
		CXXFLAGS += -O$(OPTL)
		FFLAGS   += -O$(OPTL)
	endif
	# Vectorization flags
	ifeq ($(VECTORIZATION),ON)
		CFLAGS   += -x$(HOST) -mtune=$(TUNE)
		CXXFLAGS += -x$(HOST) -mtune=$(TUNE)
		FFLAGS   += -x$(HOST) -mtune=$(TUNE)
	endif
	# OpenMP flag
	ifeq ($(OPENMP_PARALL),ON)
		CFLAGS   += -qopenmp -DUSE_OMP
		CXXFLAGS += -qopenmp -DUSE_OMP
	endif
endif
# C standard
#CFLAGS   += -std=c99
# C++ standard
CXXFLAGS += -std=c++11
# Header includes
CXXFLAGS += -I${INC_PATH}


# Defines
#
DFLAGS = -DNPY_NO_DEPRECATED_API
ifeq ($(USE_GESVF),ON)
	DFLAGS += -DUSE_LAPACK_DGESVD
endif
ifeq ($(USE_MKL),ON)
	DFLAGS += -DUSE_MKL
endif
ifeq ($(USE_FFTW),ON)
	DFLAGS += -DUSE_FFTW3
endif


# One rule to compile them all, one rule to find them,
# One rule to bring them all and in the compiler link them.
all: deps python install
	@echo ""
	@echo "pyLOM deployed successfully"

# Selection of vector_matrix kernel libraries
#
ifeq ($(USE_MKL),ON)
vector_matrix: mkl

else
vector_matrix: lapack openblas

endif

# Selection of fft kernel libraries
#
ifeq ($(USE_FFTW),ON)
fft: fftw nfft

else
fft: kissfft

endif

# General rule to build dependencies
#
deps: vector_matrix fft


# Python
#
python: setup.py
	@CC="${CC}" CFLAGS="${CFLAGS} ${DFLAGS}" CXX="${CXX}" CXXFLAGS="${CXXFLAGS} ${DFLAGS}" LDSHARED="${CC} -shared" ${PYTHON} $< build_ext --inplace
	@echo "Python programs deployed successfully"

requirements: requirements.txt
	@${PIP} install -r $<

requirements_cupy: requirements_cupy.txt
	@${PIP} install -r $<

requirements_NN: requirements_NN.txt
	@${PIP} install -r $<

requirements_optional: requirements_optional.txt
	@${PIP} install -r $<

requirements_GPR: requirements_GPR.txt
	@${PIP} install -r $<

requirements_rl: requirements_rl.txt
	@${PIP} install -r $<

requirements_full: requirements requirements_cupy requirements_NN requirements_optional requirements_rl


install: requirements python
	@CC="${CC}" CFLAGS="${CFLAGS} ${DFLAGS}" CXX="${CXX}" CXXFLAGS="${CXXFLAGS} ${DFLAGS}" LDSHARED="${CC} -shared" ${PIP} install --no-deps --use-pep517 .

install_dev: requirements python
	@CC="${CC}" CFLAGS="${CFLAGS} ${DFLAGS}" CXX="${CXX}" CXXFLAGS="${CXXFLAGS} ${DFLAGS}" LDSHARED="${CC} -shared" ${PIP} install --no-deps --use-pep517 -e .

package-build:
	@CFLAGS="${CFLAGS}" CXXFLAGS="${CXXFLAGS}" LDSHARED="${CC} -shared" ${PYTHON} -m build


# External libraries
#
lapack: Deps/lapack
	@bash $</install_lapack.sh "${LAPACK_VERS}" "${PWD}/$<" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"
openblas: Deps/lapack
	@bash $</install_openblas.sh "${OPENBLAS_VERS}" "${PWD}/$<" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"
mkl: Deps/oneAPI
	@bash $</install_mkl.sh "${PLATFORM}" "${ONEAPI_VERS}" "${PWD}/$</mkl" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"
kissfft: Deps/kissfft
	@bash $</install_kissfft.sh "${PLATFORM}" "${KISSFFT_VERS}" "${OPENMP_PARALL}" "${PWD}/$<" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"
fftw: Deps/fftw
	@bash $</install_fftw.sh "${PLATFORM}" "${FFTW_VERS}" "${OPENMP_PARALL}" "${PWD}/$<" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"
nfft: Deps/nfft
	@bash $</install_nfft.sh "${PLATFORM}" "${NFFT_VERS}" "${OPENMP_PARALL}" "${PWD}/$<" "${CC}" "${CFLAGS}" "${FC}" "${FFLAGS}"


# Generic object makers
#
%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $< $(DFLAGS)

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c -o $@ $< $(DFLAGS)

%.o: %.f
	$(FC) $(FFLAGS) -c -o $@ $< $(DFLAGS)

%.o: %.f90
	$(FC) $(FFLAGS) -c -o $@ $< $(DFLAGS)


# Clean
#
clean:
	-@cd pyLOM; rm -rf *.o $(wildcard **/*.o)
	-@cd pyLOM; rm -rf *.pyc $(wildcard **/*.pyc)
	-@cd pyLOM; rm -rf __pycache__ utils/__pycache__  MANIFOLD/__pycache__ GPR/__pycache__ GPOD/__pycache__ 
	-@cd pyLOM; rm -rf POD/__pycache__ POD/*.c POD/*.cpp POD/*.html
	-@cd pyLOM; rm -rf DMD/__pycache__ DMD/*.c DMD/*.cpp DMD/*.html
	-@cd pyLOM; rm -rf SPOD/__pycache__ SPOD/*.c SPOD/*.cpp SPOD/*.html
	-@cd pyLOM; rm -rf vmmath/__pycache__ vmmath/*.c vmmath/*.cpp vmmath/*.html
	-@cd pyLOM; rm -rf inp_out/__pycache__ inp_out/*.c inp_out/*.cpp inp_out/*.html
	-@cd pyLOM; rm -rf NN/__pycache__ NN/architectures/__pycache__ 

cleanall: clean
	-@rm -rf build
	-@cd pyLOM; rm vmmath/*.so POD/*.so DMD/*.so SPOD/*.so

ifeq ($(USE_MKL),ON)
uninstall_vector_matrix: uninstall_mkl 

else
uninstall_vector_matrix: uninstall_lapack 

endif

ifeq ($(USE_FFTW),ON)
uninstall_fft: uninstall_fftw uninstall_nfft

else
uninstall_fft: uninstall_kissfft

endif

uninstall_deps: uninstall_vector_matrix uninstall_fft

uninstall: cleanall uninstall_deps uninstall_python
	@${PIP} uninstall pyLowOrder
	-@rm -rf pyLowOrder.egg-info

uninstall_python:
	@${PIP} uninstall pyLowOrder
	-@rm -rf pyLowOrder.egg-info

uninstall_lapack: Deps/lapack/lib
	-@rm -rf Deps/lapack/include
	-@rm -rf Deps/lapack/lib
	-@rm -rf Deps/lapack/share

uninstall_mkl: Deps/oneAPI/mkl
	-@Deps/oneAPI/l_BaseKit_p_${ONEAPI_VERS}.sh -a --silent --action remove --eula accept --components intel.oneapi.lin.mkl.devel --install-dir $(shell pwd)/Deps/oneAPI
	-@rm -rf Deps/oneAPI/l_BaseKit_p_${ONEAPI_VERS}.sh Deps/oneAPI/mkl

uninstall_kissfft: Deps/kissfft/lib
	-@rm -rf Deps/kissfft/include
	-@rm -rf Deps/kissfft/lib

uninstall_fftw: Deps/fftw/lib
	-@rm -rf Deps/fftw/include
	-@rm -rf Deps/fftw/lib

uninstall_nfft: Deps/nfft/lib
	-@rm -rf Deps/nfft/include
	-@rm -rf Deps/nfft/lib
	-@rm -rf Deps/nfft/share
