# ---------------------------------------------------------------------------
# Makefile for Cloudy-ODT (CODT)
#
# A plain-make build for users who do not have the Fortran Package Manager
# (fpm). It reproduces the fpm build: gfortran, -O2, free-form long lines,
# linked against netCDF / netCDF-Fortran.
#
# The fpm build (see fpm_env + BUILD.md) remains the reference build used to
# produce the published simulations. This Makefile is a portable equivalent.
# Use at your own discretion
#
# Usage:
#   make                       # build ./CODT using NetCDF found via nf-config
#   make NETCDF_INC=... NETCDF_LIB=...   # override include/lib dirs manually
#   make clean
# ---------------------------------------------------------------------------

# FC defaults to gfortran. Override on the command line: make FC=ifort
# (a plain '=' is used because make pre-defines FC=f77, which would defeat ?=)
FC      = gfortran
FFLAGS  = -g -O2 -ffree-line-length-none

# --- NetCDF discovery ------------------------------------------------------
# By default we ask nf-config (shipped with netcdf-fortran) for the right
# flags. If nf-config is not on PATH, set NETCDF_INC / NETCDF_LIB by hand,
NF_CONFIG := $(shell command -v nf-config 2>/dev/null)

ifdef NETCDF_INC
  INCFLAGS := -I$(NETCDF_INC)
  LDFLAGS  := -L$(NETCDF_LIB) -Wl,-rpath=$(NETCDF_LIB) -lnetcdff -lnetcdf
else ifneq ($(NF_CONFIG),)
  INCFLAGS := $(shell nf-config --fflags)
  LDFLAGS  := $(shell nf-config --flibs)
else
  # Use deferred ('=') assignment so the error only fires if these flags are
  # actually expanded by a compile/link recipe. Targets like 'clean' still work.
  INCFLAGS = $(error Could not find nf-config; set NETCDF_INC and NETCDF_LIB on the make command line)
  LDFLAGS  = $(error Could not find nf-config; set NETCDF_INC and NETCDF_LIB on the make command line)
endif

# --- Sources ---------------------------------------------------------------
SRCDIR  := src
APPDIR  := app
BUILDDIR := build_make

# Objects MUST be listed in dependency (compile) order so module .mod files
# exist before the units that `use` them. Order derived from the module graph:
#   globals -> microphysics -> ODT -> special_effects -> DGM -> droplets
#           -> writeout -> write_particle -> initialize -> main
OBJS := \
  $(BUILDDIR)/globals.o \
  $(BUILDDIR)/microphysics.o \
  $(BUILDDIR)/ODT.o \
  $(BUILDDIR)/special_effects.o \
  $(BUILDDIR)/DGM.o \
  $(BUILDDIR)/droplets.o \
  $(BUILDDIR)/writeout.o \
  $(BUILDDIR)/write_particle.o \
  $(BUILDDIR)/initialize.o \
  $(BUILDDIR)/main.o

EXE := CODT

.PHONY: all clean
all: $(EXE)

$(EXE): $(OBJS)
	$(FC) $(FFLAGS) -o $@ $(OBJS) $(LDFLAGS)

# Compile rule for library modules. -J places .mod files in BUILDDIR and -I
# lets later units find them. Because $(OBJS) is ordered, prerequisite .mod
# files are already present when each unit compiles.
$(BUILDDIR)/%.o: $(SRCDIR)/%.f90 | $(BUILDDIR)
	$(FC) $(FFLAGS) $(INCFLAGS) -I$(BUILDDIR) -J$(BUILDDIR) -c $< -o $@

# Compile rule for the program in app/
$(BUILDDIR)/%.o: $(APPDIR)/%.f90 | $(BUILDDIR)
	$(FC) $(FFLAGS) $(INCFLAGS) -I$(BUILDDIR) -J$(BUILDDIR) -c $< -o $@

$(BUILDDIR):
	mkdir -p $(BUILDDIR)

clean:
	rm -rf $(BUILDDIR) $(EXE)
