aboutsummaryrefslogtreecommitdiff
path: root/reproduce/analysis
diff options
context:
space:
mode:
authorMohammad Akhlaghi <mohammad@akhlaghi.org>2019-04-15 01:47:58 +0100
committerMohammad Akhlaghi <mohammad@akhlaghi.org>2019-04-15 02:24:09 +0100
commit313b936b502d22b6a2ff43f560dee0bb51fd01d0 (patch)
tree70f884b91b393be4d3c6b7cfaeaf3412900bd16f /reproduce/analysis
parent4722ea598edd6b630227404c48c1c09ac527e9b8 (diff)
New architecture to separate software-building and analysis steps
Until now, the software building and analysis steps of the pipeline were intertwined. However, these steps (of how to build a software, and how to use it) are logically completely independent. Therefore with this commit, the pipeline now has a new architecture (particularly in the `reproduce' directory) to emphasize this distinction: The `reproduce' directory now has the two `software' and `analysis' subdirectories and the respective parts of the previous architecture have been broken up between these two based on their function. There is also no more `src' directory. The `config' directory for software and analysis is now mixed with the language-specific directories. Also, some of the software versions were also updated after some checks with their webpages. This new architecture will allow much more focused work on each part of the pipeline (to install the software and to run them for an analysis).
Diffstat (limited to 'reproduce/analysis')
-rwxr-xr-xreproduce/analysis/bash/download-multi-try112
-rw-r--r--reproduce/analysis/config/INPUTS.mk15
-rw-r--r--reproduce/analysis/config/delete-me-num.mk2
-rw-r--r--reproduce/analysis/config/pdf-build.mk21
-rw-r--r--reproduce/analysis/make/delete-me.mk126
-rw-r--r--reproduce/analysis/make/download.mk91
-rw-r--r--reproduce/analysis/make/initialize.mk339
-rw-r--r--reproduce/analysis/make/paper.mk139
-rw-r--r--reproduce/analysis/make/top.mk136
9 files changed, 981 insertions, 0 deletions
diff --git a/reproduce/analysis/bash/download-multi-try b/reproduce/analysis/bash/download-multi-try
new file mode 100755
index 0000000..1fd7497
--- /dev/null
+++ b/reproduce/analysis/bash/download-multi-try
@@ -0,0 +1,112 @@
+# Attempt downloading multiple times before crashing whole project. From
+# the top project directory (for the shebang above), this script must be
+# run like this:
+#
+# $ /path/to/download-multi-try downloader lockfile input-url downloaded-name
+#
+# NOTE: The `downloader' must contain the option to specify the output name
+# in its end. For example "wget -O". Any other option can also be placed in
+# the middle.
+#
+# Due to temporary network problems, a download may fail suddenly, but
+# succeed in a second try a few seconds later. Without this script that
+# temporary glitch in the network will permanently crash the project and
+# it can't continue. The job of this script is to be patient and try the
+# download multiple times before crashing the whole project.
+#
+# LOCK FILE: Since there is ultimately only one network port to the outside
+# world, downloading is done much faster in serial, not in parallel. But
+# the project's processing may be done in parallel (with multiple threads
+# needing to download different files at the same time). Therefore, this
+# script uses the `flock' program to only do one download at a time. To
+# benefit from it, any call to this script must be given the same lock
+# file.
+#
+# Copyright (C) 2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This script is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This script is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details. See <http://www.gnu.org/licenses/>.
+
+
+
+
+
+# Script settings
+# ---------------
+# Stop the script if there are any errors.
+set -e
+
+
+
+
+
+# Input arguments and necessary sanity checks.
+inurl="$3"
+outname="$4"
+lockfile="$2"
+downloader="$1"
+if [ "x$downloader" = x ]; then
+ echo "$0: downloader (first argument) not given."; exit 1;
+fi
+if [ "x$lockfile" = x ]; then
+ echo "$0: lock file (second argument) not given."; exit 1;
+fi
+if [ "x$inurl" = x ]; then
+ echo "$0: full input URL (third argument) not given."; exit 1;
+fi
+if [ "x$outname" = x ]; then
+ echo "$0: output name (fourth argument) not given."; exit 1;
+fi
+
+
+
+
+
+# Try downloading multiple times before crashing.
+counter=0
+maxcounter=10
+while [ ! -f "$outname" ]; do
+
+ # Increment the counter. We need the `counter=' part here because
+ # without it the evaluation of arithmetic expression will be like and
+ # error and the script is set to crash on errors.
+ counter=$((counter+1))
+
+ # If we have passed a maximum number of trials, just exit with
+ # a failed code.
+ if (( counter > maxcounter )); then
+ echo
+ echo "Failed $maxcounter download attempts: $outname"
+ echo
+ exit 1
+ fi
+
+ # If this isn't the first attempt print a notice and wait a little for
+ # the next trail.
+ if (( counter > 1 )); then
+ tstep=$((counter*5))
+ echo "Download trial $counter for '$outname' in $tstep seconds."
+ sleep $tstep
+ fi
+
+ # Attempt downloading the file (one-at-a-time). Note that the
+ # `downloader' ends with the respective option to specify the output
+ # name. For example "wget -O" (so `outname', that comes after it) will
+ # be the name of the downloaded file.
+ flock "$lockfile" bash -c \
+ "if ! $downloader $outname $inurl; then rm -f $outname; fi"
+done
+
+
+
+
+
+# Return successfully
+exit 0
diff --git a/reproduce/analysis/config/INPUTS.mk b/reproduce/analysis/config/INPUTS.mk
new file mode 100644
index 0000000..eb38295
--- /dev/null
+++ b/reproduce/analysis/config/INPUTS.mk
@@ -0,0 +1,15 @@
+# Input files necessary for this project.
+#
+# This file is read by the configure script and running Makefiles.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice and
+# this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+WFPC2IMAGE = WFPC2ASSNu5780205bx.fits
+WFPC2MD5 = a4791e42cd1045892f9c41f11b50bad8
+WFPC2SIZE = 62kb
+WFPC2URL = https://fits.gsfc.nasa.gov/samples
diff --git a/reproduce/analysis/config/delete-me-num.mk b/reproduce/analysis/config/delete-me-num.mk
new file mode 100644
index 0000000..17f608c
--- /dev/null
+++ b/reproduce/analysis/config/delete-me-num.mk
@@ -0,0 +1,2 @@
+# Number of samples to create
+delete-me-num = 50
diff --git a/reproduce/analysis/config/pdf-build.mk b/reproduce/analysis/config/pdf-build.mk
new file mode 100644
index 0000000..3a86ff3
--- /dev/null
+++ b/reproduce/analysis/config/pdf-build.mk
@@ -0,0 +1,21 @@
+# Make the final PDF?
+# -------------------
+#
+# During the project's early phases, it is usually not necessary to build
+# the PDF file (which makes a lot of output lines on the command-line and
+# can make it hard to find the commands and possible errors (and their
+# outputs). Also, in some cases, only the produced results may be of
+# interest and not the final PDF, so LaTeX (and its necessary packages) may
+# not be installed.
+#
+# If this variable is given any string, a PDF will be made with
+# LaTeX. Otherwise, a notice will just printed that for now, no PDF will be
+# created.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice and
+# this notice are preserved. This file is offered as-is, without any
+# warranty.
+pdf-build-final = yes
diff --git a/reproduce/analysis/make/delete-me.mk b/reproduce/analysis/make/delete-me.mk
new file mode 100644
index 0000000..c4cfffe
--- /dev/null
+++ b/reproduce/analysis/make/delete-me.mk
@@ -0,0 +1,126 @@
+# Dummy Makefile to create a random dataset for plotting.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This Makefile is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This Makefile is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# A copy of the GNU General Public License is available at
+# <http://www.gnu.org/licenses/>.
+
+
+
+
+
+# Dummy dataset
+# -------------
+#
+# We will use AWK to generate a table showing X and X^2 and draw its plot.
+dmdir = $(texdir)/delete-me
+dm = $(dmdir)/data.txt
+$(dmdir): | $(texdir); mkdir $@
+$(dm): $(pconfdir)/delete-me-num.mk | $(dmdir)
+
+ # When the plotted values are re-made, it is necessary to also
+ # delete the TiKZ externalized files so the plot is also re-made.
+ rm -f $(tikzdir)/delete-me.pdf
+
+ # Generate the table of random values.
+ awk 'BEGIN {for(i=1;i<=$(delete-me-num);i+=0.5) print i, i*i; }' > $@
+
+
+
+
+
+# WFPC2 image PDF
+# -----------------
+#
+# For an example image, we'll make a PDF copy of the WFPC II image to
+# display in the paper.
+dddemodir = $(texdir)/delete-me-demo
+$(dddemodir): | $(texdir); mkdir $@
+demopdf = $(dddemodir)/wfpc2.pdf
+$(demopdf): $(dddemodir)/%.pdf: $(indir)/%.fits | $(dddemodir)
+
+ # When the plotted values are re-made, it is necessary to also
+ # delete the TiKZ externalized files so the plot is also re-made.
+ rm -f $(tikzdir)/delete-me-wfpc2.pdf
+
+ # Convert the dataset to a PDF.
+ astconvertt --colormap=gray --fluxhigh=4 $< -h0 -o$@
+
+
+
+
+
+# Histogram of WFPC2 image
+# ------------------------
+#
+# For an example plot, we'll show the pixel value histogram also.
+histogram = $(dddemodir)/wfpc2-hist.txt
+$(histogram): $(dddemodir)/%-hist.txt: $(indir)/%.fits | $(dddemodir)
+
+ # When the plotted values are re-made, it is necessary to also
+ # delete the TiKZ externalized files so the plot is also re-made.
+ rm -f $(tikzdir)/delete-me-wfpc2.pdf
+
+ # Generate the pixel value distribution
+ aststatistics --lessthan=5 $< -h0 --histogram -o$@
+
+
+
+
+
+# Basic statistics
+# ----------------
+#
+# This is just as a demonstration on how to get analysic configuration
+# parameters from variables defined in `reproduce/analysis/config/'.
+stats = $(dddemodir)/wfpc2-stats.txt
+$(stats): $(dddemodir)/%-stats.txt: $(indir)/%.fits | $(dddemodir)
+ aststatistics $< -h0 --mean --median > $@
+
+
+
+
+
+# TeX macros
+# ----------
+#
+# This is how we write the necessary parameters in the final PDF.
+#
+# NOTE: In LaTeX you cannot use any non-alphabetic character in a variable
+# name.
+$(mtexdir)/delete-me.tex: $(dm) $(demopdf) $(histogram) $(stats)
+
+ # Write the number of random values used.
+ echo "\newcommand{\deletemenum}{$(delete-me-num)}" > $@
+
+ # Note that since Make variables start with a `$(', if you want to
+ # use `$' within the shell (not Make), you have to quote any
+ # occurance of `$' with another `$'. That is why there are `$$' in
+ # the AWK command below.
+ #
+ # Here, we are first using AWK to find the minimum and maximum
+ # values, then using it again to read each separately to use in the
+ # macro definition.
+ mm=$$(awk 'BEGIN{min=99999; max=-min}
+ {if($$2>max) max=$$2; if($$2<min) min=$$2;}
+ END{print min, max}' $(dm));
+ v=$$(echo "$$mm" | awk '{printf "%.3f", $$1}');
+ echo "\newcommand{\deletememin}{$$v}" >> $@
+ v=$$(echo "$$mm" | awk '{printf "%.3f", $$2}');
+ echo "\newcommand{\deletememax}{$$v}" >> $@
+
+ # Write the statistics of the WFPC2 image as a macro.
+ mean=$$(awk '{printf("%.2f", $$1)}' $(stats))
+ echo "\newcommand{\deletemewfpctwomean}{$$mean}" >> $@
+ median=$$(awk '{printf("%.2f", $$2)}' $(stats))
+ echo "\newcommand{\deletemewfpctwomedian}{$$median}" >> $@
diff --git a/reproduce/analysis/make/download.mk b/reproduce/analysis/make/download.mk
new file mode 100644
index 0000000..a721863
--- /dev/null
+++ b/reproduce/analysis/make/download.mk
@@ -0,0 +1,91 @@
+# Download all the necessary inputs if they are not already present.
+#
+# Since most systems only have one input/connection into the network,
+# downloading is essentially a serial (not parallel) operation. so the
+# recipes in this Makefile all use a single file lock to have one download
+# script running at every instant.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This Makefile is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This Makefile is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details. See <http://www.gnu.org/licenses/>.
+
+
+
+
+
+# Download input data
+# --------------------
+#
+# The input dataset properties are defined in `$(pconfdir)/INPUTS.mk'. For
+# this template we only have one dataset to enable easy processing, so all
+# the extra checks in this rule may seem redundant.
+#
+# In a real project, you will need more than one dataset. In that case,
+# just add them to the target list and add an `elif' statement to define it
+# in the recipe.
+#
+# Files in a server usually have very long names, which are mainly designed
+# for helping in data-base management and being generic. Since Make uses
+# file names to identify which rule to execute, and the scope of this
+# research project is much less than the generic survey/dataset, it is
+# easier to have a simple/short name for the input dataset and work with
+# that. In the first condition of the recipe below, we connect the short
+# name with the raw database name of the dataset.
+#
+# Download lock file: Most systems have a single connection to the
+# internet, therefore downloading is inherently done in series. As a
+# result, when more than one dataset is necessary for download, if they are
+# done in parallel, the speed will be slower than downloading them in
+# series. We thus use the `flock' program to tie/lock the downloading
+# process with a file and make sure that only one downloading event is in
+# progress at every moment.
+$(indir):; mkdir $@
+downloadwrapper = $(bashdir)/download-multi-try
+inputdatasets = $(foreach i, wfpc2, $(indir)/$(i).fits)
+$(inputdatasets): $(indir)/%.fits: | $(indir) $(lockdir)
+
+ # Set the necessary parameters for this input file.
+ if [ $* = wfpc2 ]; then
+ origname=$(WFPC2IMAGE); url=$(WFPC2URL); mdf=$(WFPC2MD5);
+ else
+ echo; echo; echo "Not recognized input dataset: '$*.fits'."
+ echo; echo; exit 1
+ fi
+
+ # Download (or make the link to) the input dataset.
+ if [ -f $(INDIR)/$$origname ]; then
+ ln -s $(INDIR)/$$origname $@
+ else
+ touch $(lockdir)/download
+ $(downloadwrapper) "wget --no-use-server-timestamps -O" \
+ $(lockdir)/download $$url/$$origname $@
+ fi
+
+ # Check the md5 sum to see if this is the proper dataset.
+ sum=$$(md5sum $@ | awk '{print $$1}')
+ if [ $$sum != $$mdf ]; then
+ wrongname=$(dir $@)/wrong-$(notdir $@)
+ mv $@ $$wrongname
+ echo; echo; echo "Wrong MD5 checksum for '$$origname' in $$wrongname"
+ echo; echo; exit 1
+ fi
+
+
+
+
+
+# Final TeX macro
+# ---------------
+#
+# It is very important to mention the address where the data were
+# downloaded in the final report.
+$(mtexdir)/download.tex: $(pconfdir)/INPUTS.mk | $(mtexdir)
+ echo "\\newcommand{\\wfpctwourl}{$(WFPC2URL)}" > $@
diff --git a/reproduce/analysis/make/initialize.mk b/reproduce/analysis/make/initialize.mk
new file mode 100644
index 0000000..a034494
--- /dev/null
+++ b/reproduce/analysis/make/initialize.mk
@@ -0,0 +1,339 @@
+# Project initialization.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This Makefile is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This Makefile is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# A copy of the GNU General Public License is available at
+# <http://www.gnu.org/licenses/>.
+
+
+
+
+
+# High-level directory definitions
+# --------------------------------
+#
+# Basic directories that are used throughout the project.
+#
+# Locks are used to make sure that an operation is done in series not in
+# parallel (even if Make is run in parallel with the `-j' option). The most
+# common case is downloads which are better done in series and not in
+# parallel. Also, some programs may not be thread-safe, therefore it will
+# be necessary to put a lock on them. This project uses the `flock' program
+# to achieve this.
+texdir = $(BDIR)/tex
+lockdir = $(BDIR)/locks
+indir = $(BDIR)/inputs
+mtexdir = $(texdir)/macros
+bashdir = reproduce/analysis/bash
+pconfdir = reproduce/analysis/config
+installdir = $(BDIR)/software/installed
+# --------- Delete for no Gnuastro ---------
+gconfdir = reproduce/software/config/gnuastro
+# ------------------------------------------
+
+
+
+
+
+# TeX build directory
+# ------------------
+#
+# In scenarios where multiple users are working on the project
+# simultaneously, they can't all build the final paper together, there will
+# be conflicts! It is possible to manage the working on the analysis, so no
+# conflict is caused in that phase, but it would be very slow to only let
+# one of the project members to build the paper at every instance
+# (independent parts of the paper can be added to it independently). To fix
+# this problem, when we are in a group setting, we'll use the user's ID to
+# create a separate LaTeX build directory for each user.
+#
+# The same logic applies to the final paper PDF: each user will create a
+# separte final PDF (for example `paper-user1.pdf' and `paper-user2.pdf')
+# and no `paper.pdf' will be built. This isn't a problem because
+# `initialize.tex' is a .PHONY prerequisite, so the rule to build the final
+# paper is always executed (even if it is present and nothing has
+# changed). So in terms of over-all efficiency and processing steps, this
+# doesn't change anything.
+ifeq (x$(GROUP-NAME),x)
+texbdir = $(texdir)/build
+final-paper = paper.pdf
+else
+user = $(shell whoami)
+texbdir = $(texdir)/build-$(user)
+final-paper = paper-$(user).pdf
+endif
+tikzdir = $(texbdir)/tikz
+
+
+
+
+
+# Original system environment
+# ---------------------------
+#
+# Before defining the local sub-environment here, we'll need to save the
+# system's environment for some scenarios (for example after `clean'ing the
+# built programs).
+sys-path := $(PATH)
+sys-rm := $(shell which rm)
+curdir := $(shell echo $$(pwd))
+
+
+
+
+
+# High level environment
+# ----------------------
+#
+# We want the full recipe to be executed in one call to the shell. Also we
+# want Make to run the specific version of Bash that we have installed
+# during `./configure' time.
+#
+# Regarding the directories, this project builds its major dependencies
+# itself and doesn't use the local system's default tools. With these
+# environment variables, we are setting it to prefer the software we have
+# build here.
+.ONESHELL:
+.SHELLFLAGS = -ec
+export CCACHE_DISABLE := 1
+export PATH := $(installdir)/bin
+export LD_LIBRARY_PATH := $(installdir)/lib
+export LDFLAGS := -L$(installdir)/lib
+export SHELL := $(installdir)/bin/bash
+export CPPFLAGS := -I$(installdir)/include
+
+
+
+
+
+# Python enviroment
+# -----------------
+#
+# The main Python environment variable is `PYTHONPATH'. However, so far we
+# have found several other Python-related environment variables on some
+# systems which might interfere. To be safe, we are removing all their
+# values.
+export PYTHONPATH := $(installdir)/lib/python/site-packages
+export PYTHONPATH3 := $(PYTHONPATH)
+export _LMFILES_ :=
+export PYTHONPATH2 :=
+export LOADEDMODULES :=
+export MPI_PYTHON_SITEARCH :=
+export MPI_PYTHON2_SITEARCH :=
+export MPI_PYTHON3_SITEARCH :=
+
+
+
+
+
+# High-level level directories
+# ----------------------------
+#
+# These are just the top-level directories for all the separate steps. The
+# directories (or possible sub-directories) for individual steps will be
+# defined and added within their own Makefiles.
+#
+# The `.SUFFIXES' rule with no prerequisite is defined to eliminate all the
+# default implicit rules. The default implicit rules are to do with
+# programming (for example converting `.c' files to `.o' files). The
+# problem they cause is when you want to debug the make command with `-d'
+# option: they add too many extra checks that make it hard to find what you
+# are looking for in the outputs.
+.SUFFIXES:
+$(lockdir): | $(BDIR); mkdir $@
+$(texbdir): | $(texdir); mkdir $@
+$(tikzdir): | $(texbdir); mkdir $@ && ln -fs $@ tex/tikz
+
+
+
+
+
+# High-level Makefile management
+# ------------------------------
+#
+# About `.PHONY': these are targets that must be built even if a file with
+# their name exists.
+#
+# Only `$(mtexdir)/initialize.tex' corresponds to a file. This is because
+# we want to ensure that the file is always built in every run: it contains
+# the project version which may change between two separate runs, even when
+# no file actually differs.
+packagebasename := $(shell echo paper-$$(git describe --dirty --always))
+packagecontents = $(texdir)/$(packagebasename)
+.PHONY: all clean dist dist-zip distclean clean-mmap $(packagecontents) \
+ $(mtexdir)/initialize.tex
+
+# --------- Delete for no Gnuastro ---------
+clean-mmap:; rm -f reproduce/config/gnuastro/mmap*
+# ------------------------------------------
+
+clean: clean-mmap
+ # Delete the top-level PDF file.
+ rm -f *.pdf
+
+ # Delete all the built outputs except the dependency
+ # programs. We'll use Bash's extended options builtin (`shopt') to
+ # enable "extended glob" (for listing of files). It allows extended
+ # features like ignoring the listing of a file with `!()' that we
+ # are using afterwards.
+ shopt -s extglob
+ rm -rf $(BDIR)/!(dependencies)
+
+distclean: clean
+ # We'll be deleting the built environent programs and just need the
+ # `rm' program. So for this recipe, we'll use the host system's
+ # `rm', not our own.
+ $(sys-rm) -rf $(BDIR) reproduce/build
+ $(sys-rm) -f Makefile .gnuastro .local
+ $(sys-rm) -f $(pconfdir)/LOCAL.mk $(gconfdir)/gnuastro-local.conf
+
+
+
+
+
+# Packaging rules
+# ---------------
+#
+# With the rules in this section, you can package the project in a state
+# that is ready for building the final PDF with LaTeX. This is useful for
+# collaborators who only want to contribute to the text of your project,
+# without having to worry about the technicalities of the analysis.
+$(packagecontents): | $(texdir)
+
+ # Set up the output directory, delete it if it exists and remake it
+ # to fill with new contents.
+ dir=$(texdir)/$(packagebasename)
+ rm -rf $$dir
+ mkdir $$dir
+
+ # Build a small Makefile to help in automatizing the paper building
+ # (including the bibliography).
+ m=$$dir/Makefile
+ echo "paper.pdf: paper.tex paper.bbl" > $$m
+ printf "\tpdflatex -shell-escape -halt-on-error paper\n" >> $$m
+ echo "paper.bbl: tex/src/references.tex" >> $$m
+ printf "\tpdflatex -shell-escape -halt-on-error paper\n" >> $$m
+ printf "\tbiber paper\n" >> $$m
+ echo ".PHONY: clean" >> $$m
+ echo "clean:" >> $$m
+ printf "\trm -f *.aux *.auxlock *.bbl *.bcf\n" >> $$m
+ printf "\trm -f *.blg *.log *.out *.run.xml\n" >> $$m
+
+ # Copy the top-level contents into it.
+ cp configure COPYING for-group README.md README-hacking.md $$dir/
+
+ # Build the top-level directories.
+ mkdir $$dir/reproduce $$dir/tex $$dir/tex/tikz $$dir/tex/build
+
+ # Copy all the necessary `reproduce' and `tex' contents.
+ shopt -s extglob
+ cp -r tex/src $$dir/tex/src
+ cp tex/tikz/*.pdf $$dir/tex/tikz
+ cp -r reproduce/ $$dir/reproduce
+ cp -r tex/build/!($(packagebasename)) $$dir/tex/build
+
+ # Clean up un-necessary/local files: 1) the $(texdir)/build*
+ # directories (when building in a group structure, there will be
+ # `build-user1', `build-user2' and etc), are just temporary LaTeX
+ # build files and don't have any relevant/hand-written files in
+ # them. 2) The `LOCAL.mk' and `gnuastro-local.conf' files just have
+ # this machine's local settings and are irrelevant for anyone else.
+ rm -rf $$dir/tex/build/build*
+ rm $$dir/reproduce/software/config/installation/LOCAL.mk
+ rm $$dir/reproduce/software/config/gnuastro/gnuastro-local.conf
+
+ # PROJECT SPECIFIC: under this comment, copy any other file for
+ # packaging, or remove any of the copied files above to suite your
+ # project.
+
+ # Since the packaging is mainly intended for high-level building of
+ # the PDF with LaTeX, we'll comment the `makepdf' LaTeX macro in
+ # the paper.
+ sed -e's|\\newcommand{\\makepdf}{}|%\\newcommand{\\makepdf}{}|' \
+ paper.tex > $$dir/paper.tex
+
+ # Just in case the package users want to rebuild some of the
+ # figures (manually un-comments the `makepdf' command we commented
+ # above), correct the TikZ external directory, so the figures can
+ # be rebuilt.
+ pgfsettings="$$dir/tex/src/preamble-pgfplots.tex"
+ sed -e's|{tikz/}|{tex/tikz/}|' $$pgfsettings > $$pgfsettings.new
+ mv $$pgfsettings.new $$pgfsettings
+
+ # Clean temporary (currently those ending in `~') files.
+ cd $(texdir)
+ find $(packagebasename) -name \*~ -delete
+
+# Package into `.tar.gz'.
+dist: $(packagecontents)
+ curdir=$$(pwd)
+ cd $(texdir)
+ tar -cf $(packagebasename).tar $(packagebasename)
+ gzip -f --best $(packagebasename).tar
+ cd $$curdir
+ mv $(texdir)/$(packagebasename).tar.gz ./
+
+# Package into `.zip'.
+dist-zip: $(packagecontents)
+ curdir=$$(pwd)
+ cd $(texdir)
+ zip -q -r $(packagebasename).zip $(packagebasename)
+ cd $$curdir
+ mv $(texdir)/$(packagebasename).zip ./
+
+
+
+
+
+# Check the version of programs which write their version
+# -------------------------------------------------------
+pvcheck = prog="$(strip $(1))"; \
+ ver="$(strip $(2))"; \
+ name="$(strip $(3))"; \
+ macro="$(strip $(4))"; \
+ verop="$(strip $(5))"; \
+ if [ "x$$verop" = x ]; then V="--version"; else V=$$verop; fi; \
+ v=$$($$prog $$V | awk '/'$$ver'/{print "y"; exit 0}'); \
+ if [ x$$v != xy ]; then \
+ echo; echo "PROJECT ERROR: Not running $$name $$ver"; echo; \
+ exit 1; \
+ fi; \
+ echo "\newcommand{\\$$macro}{$$ver}" >> $@
+
+lvcheck = idir=$(BDIR)/dependencies/installed/include; \
+ f="$$idir/$(strip $(1))"; \
+ ver="$(strip $(2))"; \
+ name="$(strip $(3))"; \
+ macro="$(strip $(4))"; \
+ v=$$(awk '/^\#/&&/define/&&/'$$ver'/{print "y";exit 0}' $$f); \
+ if [ x$$v != xy ]; then \
+ echo; echo "PROJECT ERROR: Not linking with $$name $$ver"; \
+ echo; exit 1; \
+ fi; \
+ echo "\newcommand{\\$$macro}{$$ver}" >> $@
+
+
+
+
+# Project initialization results
+# ------------------------------
+#
+# This file will store some basic info about the project that is necessary
+# for the final PDF. Since these are not version controlled, it must be
+# calculated everytime the project is run. So even though this file
+# actually exists, it is also aded as a `.PHONY' target above.
+$(mtexdir)/initialize.tex: | $(mtexdir)
+
+ # Version of the project.
+ @v=$$(git describe --dirty --always);
+ echo "\newcommand{\projectversion}{$$v}" > $@
diff --git a/reproduce/analysis/make/paper.mk b/reproduce/analysis/make/paper.mk
new file mode 100644
index 0000000..5378ee3
--- /dev/null
+++ b/reproduce/analysis/make/paper.mk
@@ -0,0 +1,139 @@
+# Build the final PDF paper/report.
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This Makefile is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This Makefile is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# A copy of the GNU General Public License is available at
+# <http://www.gnu.org/licenses/>.
+
+
+
+
+# LaTeX macros for paper
+# ----------------------
+#
+# To report the input settings and results, the final report's PDF (final
+# target of this project) uses macros generated from various steps of the
+# project. All these macros are defined through `$(mtexdir)/project.tex'.
+#
+# `$(mtexdir)/project.tex' is actually just a combination of separate files
+# that keep the LaTeX macros related to each workhorse Makefile (in
+# `reproduce/src/make/*.mk'). Those individual macros are pre-requisites to
+# `$(mtexdir)/project.tex'. The only workhorse Makefile that doesn't need
+# to produce LaTeX macros is this Makefile (`reproduce/src/make/paper.mk').
+#
+# This file is thus the interface between the processing scripts and the
+# final PDF: when we get to this point, all the processing has been
+# completed.
+#
+# Note that if you don't want the final PDF and just want the processing
+# and file outputs, you can remove the value of `pdf-build-final' in
+# `reproduce/analysis/config/pdf-build.mk'.
+$(mtexdir)/project.tex: $(foreach s, $(subst paper,,$(makesrc)), $(mtexdir)/$(s).tex)
+
+ # If no PDF is requested, or if LaTeX isn't available, don't
+ # continue to building the final PDF. Otherwise, merge all the TeX
+ # macros into one for building the PDF.
+ @if [ -f .local/bin/pdflatex ] && [ x"$(pdf-build-final)" != x ]; then
+
+ # Put a LaTeX input command for all the necessary macro files.
+ rm -f $(mtexdir)/project.tex
+ for t in $(subst paper,,$(makesrc)); do
+ echo "\input{tex/build/macros/$$t.tex}" >> $(mtexdir)/project.tex
+ done
+ else
+ echo
+ echo "-----"
+ echo "The processing has COMPLETED SUCCESSFULLY! But the final "
+ echo "LaTeX-built PDF paper will not be built."
+ echo
+ if [ x$(more-on-building-pdf) = x1 ]; then
+ echo "To do so, make sure you have LaTeX within the project (you"
+ echo "can check by running './.local/bin/latex --version'), _AND_"
+ echo "make sure that the 'pdf-build-final' variable has a value."
+ echo "'pdf-build-final' is defined in: "
+ echo "'reproduce/analysis/config/pdf-build.mk'."
+ echo
+ echo "If you don't have LaTeX within the project, please re-run"
+ echo "'./configure' when you have internet access. To speed it up,"
+ echo "you can keep the previous configuration files (answer 'n'"
+ echo "when it asks about re-writing previous configuration files)."
+ else
+ echo "For more, run './.local/bin/make more-on-building-pdf=1'"
+ fi
+ echo
+ echo "" > $@
+ fi
+
+
+
+
+
+# The bibliography
+# ----------------
+#
+# We need to run the `biber' program on the output of LaTeX to generate the
+# necessary bibliography before making the final paper. So we'll first have
+# one run of LaTeX (similar to the `paper.pdf' recipe), then `biber'.
+#
+# NOTE: `$(mtexdir)/project.tex' is an order-only-prerequisite for
+# `paper.bbl'. This is because we need to run LaTeX in both the `paper.bbl'
+# recipe and the `paper.pdf' recipe. But if `tex/src/references.tex' hasn't
+# been modified, we don't want to re-build the bibliography, only the final
+# PDF.
+$(texbdir)/paper.bbl: tex/src/references.tex \
+ | $(tikzdir) $(texbdir) $(mtexdir)/project.tex
+ # If `$(mtexdir)/project.tex' is empty, don't build PDF.
+ @macros=$$(cat $(mtexdir)/project.tex)
+ if [ x"$$macros" != x ]; then
+
+ # We'll run LaTeX first to generate the `.bcf' file (necessary
+ # for `biber') and then run `biber' to generate the `.bbl' file.
+ p=$$(pwd);
+ export TEXINPUTS=$$p:$$TEXINPUTS;
+ cd $(texbdir);
+ pdflatex -shell-escape -halt-on-error $$p/paper.tex;
+ biber paper
+
+ fi
+
+
+
+
+
+# The final paper
+# ---------------
+#
+# Run LaTeX in the `$(texbdir)' directory so all the intermediate and
+# auxiliary files stay there and keep the top directory clean. To be able
+# to run everything cleanly from there, it is necessary to add the current
+# directory (top project directory) to the `TEXINPUTS' environment
+# variable.
+paper.pdf: $(mtexdir)/project.tex paper.tex $(texbdir)/paper.bbl \
+ | $(tikzdir) $(texbdir)
+
+ # If `$(mtexdir)/project.tex' is empty, don't build the PDF.
+ @macros=$$(cat $(mtexdir)/project.tex)
+ if [ x"$$macros" != x ]; then
+
+ # Go into the top TeX build directory and make the paper.
+ p=$$(pwd)
+ export TEXINPUTS=$$p:$$TEXINPUTS
+ cd $(texbdir)
+ pdflatex -shell-escape -halt-on-error $$p/paper.tex
+
+ # Come back to the top project directory and copy the built PDF
+ # file here.
+ cd $$p
+ cp $(texbdir)/$@ $(final-paper)
+
+ fi
diff --git a/reproduce/analysis/make/top.mk b/reproduce/analysis/make/top.mk
new file mode 100644
index 0000000..a85c530
--- /dev/null
+++ b/reproduce/analysis/make/top.mk
@@ -0,0 +1,136 @@
+# Top-level Makefile (first to be loaded).
+#
+# Copyright (C) 2018-2019 Mohammad Akhlaghi <mohammad@akhlaghi.org>
+#
+# This Makefile is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This Makefile is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# A copy of the GNU General Public License is available at
+# <http://www.gnu.org/licenses/>.
+
+
+
+
+
+# Load the local configuration (created after running `./configure').
+include reproduce/software/config/installation/LOCAL.mk
+
+
+
+
+
+# Ultimate target of this project
+# -------------------------------
+#
+# The final paper/report (`paper.pdf') is the main target of this
+# project. As defined in the Make paradigm, it must be the first target
+# that Make encounters (immediately after loading the local configuration
+# settings, necessary for a group building scenario mentioned next).
+#
+#
+# Group build
+# -----------
+#
+# This project can also be configured to have a shared build directory
+# between multiple users. In this scenario, many users (on a server) can
+# have their own/separate version controlled project source, but share the
+# same build outputs (in a common directory). This will allow a group to
+# work separately, on parallel parts of the analysis that don't
+# interfere. It is thus very useful in cases were special storage
+# requirements or CPU power is necessary and its not possible/efficient for
+# each user to have a fully separate copy of the build directory.
+#
+# Controlling this requires two variables that are available at this stage:
+#
+# - `GROUP-NAME': from `LOCAL.mk' (which was built by `./configure').
+# - `reproducible_paper_group_name': from the `./for-group' script (if it
+# was used to call Make).
+#
+# The analysis is only done when both have the same group name. Note that
+# when the project isn't being built for a group, both variables will be an
+# empty string.
+#
+#
+# Only processing, no LaTeX PDF
+# -----------------------------
+#
+# If you are just interested in the processing and don't want to build the
+# PDF, you can skip the creatation of the final PDF by removing the value
+# of `pdf-build-final' in `reproduce/analysis/config/pdf-build.mk'.
+ifeq (x$(reproducible_paper_group_name),x$(GROUP-NAME))
+all: paper.pdf
+else
+all:
+ @if [ "x$(GROUP-NAME)" = x ]; then \
+ echo "Project is NOT configured for groups, please run"; \
+ echo " $$ .local/bin/make"; \
+ else \
+ echo "Project is configured for groups, please run"; \
+ echo " $$ ./for-group $(GROUP-NAME) make -j8"; \
+ fi
+endif
+
+
+
+
+
+# Define source Makefiles
+# -----------------------
+#
+# To keep things clean, managable and readable, each set of operations
+# is (and must be) classified (modularized) by context into separate
+# Makefiles: the more the better. These modular steps are then
+# included in this top-level Makefile through the `include' command of
+# the next step. Each Makefile should also produce a LaTeX macro file
+# with the same fixed name (used to keep all the parameters and
+# relevant outputs of the steps in it for the final paper).
+#
+# In the rare case that no special LaTeX macros are necessary in a
+# workhorse Makefile, you can simply make an empty file with `touch
+# $@'. This will not add any lines to the final combined LaTeX macros
+# file, but will create the file that is a prerequisite to the final
+# paper generation.
+#
+# To (significantly) help in readability, this top-level Makefile should be
+# the only one in charge of including Makefiles. So if you care about easy
+# maintainence and understandability (even for your self, in one year! It
+# is VERY IMPORTANT and as a scientist, you MUST care about it!), do not
+# include Makefiles from any other Makefile.
+#
+# IMPORTANT NOTE: order matters in the inclusion of the processing
+# Makefiles. As the project grows, some Makefiles will define
+# variables/dependencies that later Makefiles need. Therefore we are using
+# a `foreach' loop in the next step to explicitly request loading them in
+# the same order that they are defined here (we aren't just using a
+# wild-card like the configuration Makefiles).
+makesrc = initialize \
+ download \
+ delete-me \
+ paper
+
+
+
+
+
+# Include all analysis Makefiles
+# ------------------------------
+#
+# 1) All the analysis configuration-Makefiles (Makefiles that only define
+# variables with no rules or order).
+#
+# 2) From the software configuration-Makefiles, we only include the one
+# containing software versions, just incase its necessary to
+# use/report outside of the acknowledgments section of the paper.
+#
+# 3) Finally, we'll import all the analysis workhorse-Makefiles which
+# contain rules to actually do this project's processing.
+include reproduce/analysis/config/*.mk
+include reproduce/software/config/installation/versions.mk
+include $(foreach s,$(makesrc), reproduce/analysis/make/$(s).mk)