From 083548de07e9dd7ccb17d962bb3e253d656c0a83 Mon Sep 17 00:00:00 2001
From: loikki <loic.hausammann@protonmail.ch>
Date: Wed, 13 Feb 2019 09:00:55 +0100
Subject: [PATCH] Start implementing PySWIFTsim as a subproject of SWIFT

---
 AUTHORS                               |   2 +
 COPYING                               |   1 +
 ChangeLog                             |   0
 INSTALL                               |   1 +
 Makefile.am                           |  22 +++
 NEWS                                  |   0
 README                                |   1 +
 configure.ac                          | 145 +++++++++++++++
 examples/cooling_rate/cooling.yml     |  11 ++
 examples/cooling_rate/plot_cooling.py | 229 ++++++-----------------
 src/Makefile.am                       |   2 +-
 src/cooling_wrapper.c                 | 257 ++++----------------------
 src/cooling_wrapper.h                 |   4 -
 src/part_wrapper.c                    |  35 +---
 src/part_wrapper.h                    |  14 +-
 src/pyswiftsim.h                      |  32 ++++
 src/pyswiftsim_tools.h                |   9 +-
 src/wrapper.c                         |  24 ---
 18 files changed, 321 insertions(+), 468 deletions(-)
 create mode 100644 AUTHORS
 create mode 120000 COPYING
 create mode 100644 ChangeLog
 create mode 120000 INSTALL
 create mode 100644 Makefile.am
 create mode 100644 NEWS
 create mode 120000 README
 create mode 100644 configure.ac
 create mode 100644 src/pyswiftsim.h

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..d202675
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Loic Hausammann		loic.hausammann@epfl.ch
+Yves Revaz   		yves.revaz@epfl.ch
diff --git a/COPYING b/COPYING
new file mode 120000
index 0000000..88798ab
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+/usr/share/automake-1.15/COPYING
\ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 120000
index 0000000..ddcdb76
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1 @@
+/usr/share/automake-1.15/INSTALL
\ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..4daa85e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,22 @@
+# This file is part of SWIFT.
+# Copyright (c) 2012 pedro.gonnet@durham.ac.uk
+#               2015 matthieu.schaller@durham.ac.uk
+# 
+# This program 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 program 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.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Automake stuff
+ACLOCAL_AMFLAGS = -I m4
+
+# Show the way...
+SUBDIRS = src
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/README b/README
new file mode 120000
index 0000000..602d87d
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+Readme.md
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f9353c5
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,145 @@
+# This file is part of SWIFT.
+# Copyright (C) 2012 pedro.gonnet@durham.ac.uk.
+#               2016 p.w.draper@durham.ac.uk.
+#
+# This program 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 program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Init the project.
+AC_INIT([PySWIFTsim],[0.1.0],[https://gitlab.cosma.dur.ac.uk/swift/PySWIFTsim])
+
+swift_config_flags="$*"
+
+#  We want to stop when given unrecognised options. No subdirs so this is safe.
+enable_option_checking=${enable_option_checking:-fatal}
+if test -n "$ac_unrecognized_opts"; then
+    case $enable_option_checking in
+        no)
+        ;;
+        fatal)
+            { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+              { (exit 1); exit 1; }; }
+        ;;
+        *)
+            $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2
+        ;;
+    esac
+fi
+
+AC_COPYRIGHT
+AC_CONFIG_SRCDIR([src/wrapper.c])
+AC_CONFIG_AUX_DIR([.])
+AM_INIT_AUTOMAKE([subdir-objects])
+
+# Add local macro collection.
+AC_CONFIG_MACRO_DIR([m4])
+
+# Stop default CFLAGS from anyone except the environment.
+: ${CFLAGS=""}
+
+# Generate header file.
+AM_CONFIG_HEADER(config.h)
+
+# Find and test the compiler.
+AX_CHECK_ENABLE_DEBUG
+AC_PROG_CC
+AM_PROG_CC_C_O
+
+# Enable POSIX and platform extension preprocessor macros.
+AC_USE_SYSTEM_EXTENSIONS
+
+# Check for compiler version and vendor.
+AX_COMPILER_VENDOR
+AX_COMPILER_VERSION
+
+#  Restrict support.
+AC_C_RESTRICT
+
+
+# Add libtool support (now that CC is defined).
+LT_INIT
+
+# Need C99 and inline support.
+AC_PROG_CC_C99
+AC_C_INLINE
+
+# Need fortran for grackle and velociraptor
+AC_PROG_FC
+AC_FC_LIBRARY_LDFLAGS
+
+
+# Define HAVE_POSIX_MEMALIGN if it works.
+AX_FUNC_POSIX_MEMALIGN
+
+# Autoconf stuff.
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_HEADER_STDC
+
+SWIFT_ADD_LIBRARIES
+
+SWIFT_ADD_SPECIAL_FLAGS
+
+# this one should be at the beginning
+# it overwrites all the required parameters
+SWIFT_ADD_SUBGRID_MODELS
+
+
+
+SWIFT_ADD_GRAVITY
+
+SWIFT_ADD_HYDRO
+
+SWIFT_ADD_STARS
+
+SWIFT_ADD_KERNEL
+
+SWIFT_ADD_DIMENSION
+
+SWIFT_ADD_EQUATION_OF_STATE
+
+SWIFT_ADD_CHEMISTRY
+
+SWIFT_ADD_COOLING
+
+SWIFT_ADD_RIEMANN
+
+SWIFT_ADD_TRACER
+
+PYSWIFT_ADD_PYTHON
+
+# Check for git, needed for revision stamps.
+AC_PATH_PROG([GIT_CMD], [git])
+AC_SUBST([GIT_CMD])
+
+# Make the documentation. Add conditional to handle disable option.
+DX_INIT_DOXYGEN(libswift,doc/Doxyfile,doc/)
+AM_CONDITIONAL([HAVE_DOXYGEN], [test "$ac_cv_path_ac_pt_DX_DOXYGEN" != ""])
+
+# Check if using EAGLE cooling
+AM_CONDITIONAL([HAVEEAGLECOOLING], [test $with_cooling = "EAGLE"])
+
+# Handle .in files.
+AC_CONFIG_FILES([Makefile src/Makefile])
+
+# Save the compilation options
+AC_DEFINE_UNQUOTED([PYSWIFT_CONFIG_FLAGS],["$swift_config_flags"],[Flags passed to configure])
+
+# Make sure the latest git revision string gets included, when we are
+# working in a checked out repository.
+test -d ${srcdir}/.git && touch ${srcdir}/src/version.c
+
+AC_DEFINE([PYSWIFT_PACKAGE_URL],["www.swiftsim.com"], [Package web pages])
+
+# Generate output.
+AC_OUTPUT
diff --git a/examples/cooling_rate/cooling.yml b/examples/cooling_rate/cooling.yml
index 0dd7d8b..ba04594 100644
--- a/examples/cooling_rate/cooling.yml
+++ b/examples/cooling_rate/cooling.yml
@@ -34,6 +34,17 @@ InitialConditions:
   file_name:  ./sedov.hdf5          # The file to read
   h_scaling:           3.33
 
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.0078125     # Initial scale-factor of the simulation
+  a_end:          1.0           # Final scale factor of the simulation
+  Omega_m:        0.307         # Matter density parameter
+  Omega_lambda:   0.693         # Dark-energy density parameter
+  Omega_b:        0.0455        # Baryon density parameter
+  Omega_r:        0.            # (Optional) Radiation density parameter
+  w_0:            -1.0          # (Optional) Dark-energy equation-of-state parameter at z=0.
+  w_a:            0.            # (Optional) Dark-energy equation-of-state time evolution parameter.
 
 # Cooling with Grackle 2.0
 GrackleCooling:
diff --git a/examples/cooling_rate/plot_cooling.py b/examples/cooling_rate/plot_cooling.py
index 4471dea..a8096db 100644
--- a/examples/cooling_rate/plot_cooling.py
+++ b/examples/cooling_rate/plot_cooling.py
@@ -17,21 +17,31 @@ You should have received a copy of the GNU Lesser General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-from pyswiftsim import wrapper
+from libpyswiftsim import coolingRate
 
 from copy import deepcopy
 import numpy as np
 import matplotlib.pyplot as plt
-from astropy import units
+from astropy import units, constants
 from os.path import isfile
 from h5py import File
+import yaml
 
 plt.rc('text', usetex=True)
 
 # PARAMETERS
+# cosmology
+with_cosmo = 0
 
 # grackle primordial chemistry (for comparison)
-primordial_chemistry = 3
+primordial_chemistry = 0
+
+# grackle simulation
+grackle_simulation = 0
+grackle_simulation = "Simulation {}".format(grackle_simulation)
+
+# name of this simulation
+simulation_name = "Grackle"
 
 # reference data
 grackle_filename = "grackle.hdf5"
@@ -98,7 +108,7 @@ def get_fields(primordial_chemistry):
     return fields
 
 
-def generate_default_initial_condition(us, pconst):
+def generate_default_initial_condition(us):
     print("Generating default initial conditions")
     d = {}
     # generate grid
@@ -108,88 +118,50 @@ def generate_default_initial_condition(us, pconst):
     d["temperature"] = T
 
     # Deal with units
-    rho *= us.UnitLength_in_cgs**3 * pconst.const_proton_mass
+    m_p = constants.m_p.to("{} g".format(us["UnitLength_in_cgs"]))
+    rho *= us["UnitLength_in_cgs"]**3 * m_p
     d["density"] = rho
 
-    energy = pconst.const_boltzmann_k * T / us.UnitTemperature_in_cgs
-    energy /= (gamma - 1.) * pconst.const_proton_mass
+    unit_time = us["UnitLength_in_cgs"] / us["UnitVelocity_in_cgs"]
+    unit_energy = us["UnitMass_in_cgs"] * us["UnitLength_in_cgs"]**2
+    unit_energy /= unit_time**2
+    k_B = constants.k_B.to("{} J / {} K".format(
+        unit_energy, us["UnitTemp_in_cgs"]
+    ))
+    energy = k_B * T / us["UnitTemp_in_cgs"]
+    energy /= (gamma - 1.) * m_p
     d["energy"] = energy
 
-    dt = default_dt / us.UnitTime_in_cgs
+    dt = default_dt / unit_time
     d["time_step"] = dt
 
     return d
 
 
-def get_io_fields(cooling, chemistry, output):
-    a = 1. / (1. + cooling.redshift)
-    fields = {
-        "MetalCooling": cooling.with_metal_cooling,
-        "UVBackground": cooling.with_uv_background,
-        "SelfShieldingMethod": cooling.self_shielding_method,
-        "MetalMassFraction": chemistry.initial_metallicity,
-        "ScaleFactor": a,
-    }
-
-    if output:
-        fields.update({
-            "MaxIter": cooling.max_step,
-            "Tolerance": cooling.convergence_limit,
-        })
-    return fields
-
-
-def getSimulationIndice(data, cooling, chemistry, output):
-
-    fields = get_io_fields(cooling, chemistry, output)
-
-    ind = 0
-    for name in data:
-        test = True
-        d = data[name]
-        if "Params" in d:
-            tmp = d["Params"]
-            for key in fields.keys():
-                check = abs(tmp.attrs[key] - fields[key]) > \
-                        1e-3 * tmp.attrs[key]
-                if check:
-                    test = False
-                    break
-        if test:
-            break
-        ind += 1
-    if ind == len(data):
-        return -1
-    else:
-        return ind
-
-
-def read_grackle_data(filename, us, primordial_chemistry, cooling, chemistry):
+def read_grackle_data(filename, us):
     print("Reading initial conditions")
     f = File(filename, "r")
     data = f["PrimordialChemistry%i" % primordial_chemistry]
 
-    i = getSimulationIndice(data, cooling, chemistry, output=False)
-    if i < 0:
-        raise IOError("Unable to locate corresponding grackle simulation")
-    else:
-        tmp = list(data.keys())
-        data = data[tmp[i]]
+    data = data[grackle_simulation]
 
     # read units
     tmp = data["Units"].attrs
 
-    u_len = tmp["Length"] / us.UnitLength_in_cgs
-    u_den = tmp["Density"] * us.UnitLength_in_cgs**3 / us.UnitMass_in_cgs
-    u_time = tmp["Time"] / us.UnitTime_in_cgs
+    u_len = tmp["Length"] / float(us["UnitLength_in_cgs"])
+    u_den = tmp["Density"] * float(us["UnitLength_in_cgs"])**3
+    u_den /= float(us["UnitMass_in_cgs"])
+    u_time = float(us["UnitLength_in_cgs"]) / float(us["UnitVelocity_in_cgs"])
+    u_time = tmp["Time"] / u_time
 
     # read input
     tmp = data["Input"]
 
+    d = {}
     energy = tmp["Energy"][:] * u_len**2 / u_time**2
     d["energy"] = energy
 
-    T = tmp["Temperature"][:] / us.UnitTemperature_in_cgs
+    T = tmp["Temperature"][:] / float(us["UnitTemp_in_cgs"])
     d["temperature"] = T
 
     density = tmp["Density"][:] * u_den
@@ -215,32 +187,10 @@ def read_grackle_data(filename, us, primordial_chemistry, cooling, chemistry):
     return d
 
 
-def initialize_swift(filename):
-    print("Initialization of SWIFT")
-    d = {}
-
-    # parse swift params
-    params = wrapper.parserReadFile(filename)
-    d["params"] = params
-
-    # init units
-    us, pconst = wrapper.unitSystemInit(params)
-    d["us"] = us
-    d["pconst"] = pconst
-
-    # init cosmo
-    cosmo = wrapper.cosmologyInit(params, us, pconst)
-    d["cosmo"] = cosmo
-
-    # init cooling
-    cooling = wrapper.coolingInit(params, us, pconst)
-    d["cooling"] = cooling
-
-    # init chemistry
-    chemistry = wrapper.chemistryInit(params, us, pconst)
-    d["chemistry"] = chemistry
-
-    return d
+def getParser(filename):
+    with open(filename, "r") as stream:
+        stream = yaml.load(stream)
+        return stream
 
 
 def plot_solution(rate, data, us):
@@ -255,16 +205,19 @@ def plot_solution(rate, data, us):
         grackle_rate = data["rate"]
 
     # change units => cgs
-    rho *= us.UnitMass_in_cgs / us.UnitLength_in_cgs**3
+    u_m = float(us["UnitMass_in_cgs"])
+    u_l = float(us["UnitLength_in_cgs"])
+    u_t = float(us["UnitLength_in_cgs"]) / float(us["UnitVelocity_in_cgs"])
+    rho *= u_m / u_l**3
 
-    T *= us.UnitTemperature_in_cgs
+    T *= float(us["UnitTemp_in_cgs"])
 
-    energy *= us.UnitLength_in_cgs**2 / us.UnitTime_in_cgs**2
+    energy *= u_l**2 / u_t**2
 
-    rate *= us.UnitLength_in_cgs**2 / us.UnitTime_in_cgs**3
+    rate *= u_l**2 / u_t**3
 
     if ref:
-        grackle_rate *= us.UnitLength_in_cgs**2 / us.UnitTime_in_cgs**3
+        grackle_rate *= u_l**2 / u_t**3
 
     # lambda cooling
     lam = rate * rho
@@ -274,13 +227,10 @@ def plot_solution(rate, data, us):
 
     # do plot
     if N_rho == 1:
-        # save data
-        write_solution(T, rho, lam)
-
         # plot Lambda vs T
         plt.figure()
         plt.loglog(T, np.abs(lam),
-                   label="SWIFT, %s" % wrapper.configGetCooling())
+                   label="SWIFT")
         if ref:
             # plot reference
             plt.loglog(T, np.abs(grackle_lam),
@@ -334,81 +284,25 @@ def plot_solution(rate, data, us):
         plt.show()
 
 
-def write_solution(T, rho, lam):
-    f = File(swift_output_filename, "a")
-
-    # create data set for this cooling
-    data_name = wrapper.configGetCooling()
-
-    if data_name not in f:
-        print("Creating Dataset")
-        data = f.create_group(data_name)
-    else:
-        data = f[data_name]
-
-    i = getSimulationIndice(data, cooling, chemistry, output=True)
-    if i != -1:
-        print("Updating Simulation")
-        keys = list(data.keys())
-        data.pop(keys[i])
-
-    data = data.create_group("Simulation %i" % len(data))
-
-    tmp = data.create_group("Units")
-    tmp.attrs["UnitSystem"] = "cgs"
-
-    tmp = data.create_group("Params")
-    fields = get_io_fields(cooling, chemistry, output=True)
-    for key in fields.keys():
-        tmp.attrs[key] = fields[key]
-
-    # temperature
-    dset = data.create_dataset(
-        "Temperature", T.shape, dtype=T.dtype)
-    dset[:] = T
-
-    # density
-    dset = data.create_dataset(
-        "Density", rho.shape, dtype=rho.dtype)
-    dset[:] = rho
-
-    # cooling rate
-    dset = data.create_dataset(
-        "Lambda", lam.shape, dtype=lam.dtype)
-    dset[:] = lam
-
-    f.close()
-
-
 if __name__ == "__main__":
 
-    d = initialize_swift(filename)
-    pconst = d["pconst"]
-    us = d["us"]
-    params = d["params"]
-    cosmo = d["cosmo"]
-    cooling = d["cooling"]
-    chemistry = d["chemistry"]
+    parser = getParser(filename)
+    us = parser["InternalUnitSystem"]
 
     if isfile(grackle_filename) and N_rho == 1:
-        d = read_grackle_data(grackle_filename, us,
-                              primordial_chemistry, cooling,
-                              chemistry)
+        d = read_grackle_data(grackle_filename, us)
     else:
-        d = generate_default_initial_condition(us, pconst)
+        d = generate_default_initial_condition(us)
 
     # du / dt
     print("Computing cooling...")
     rate = np.zeros(d["density"].shape)
 
     if compute_equilibrium:
-        rate = wrapper.coolingRate(pconst, us,
-                                   cosmo,
-                                   cooling,
-                                   chemistry,
-                                   d["density"].astype(np.float32),
-                                   d["energy"].astype(np.float32),
-                                   d["time_step"])
+        rate = coolingRate(filename, with_cosmo,
+                           d["density"].astype(np.float32),
+                           d["energy"].astype(np.float32),
+                           d["time_step"])
     else:
         fields = get_fields(primordial_chemistry)
         N = len(fields)
@@ -416,13 +310,10 @@ if __name__ == "__main__":
         for i in range(N):
             frac[:, i] = d[fields[i]]
 
-        rate = wrapper.coolingRate(pconst, us,
-                                   cosmo,
-                                   cooling,
-                                   chemistry,
-                                   d["density"].astype(np.float32),
-                                   d["energy"].astype(np.float32),
-                                   d["time_step"],
-                                   frac.astype(np.float32))
+        rate = coolingRate(filename, with_cosmo,
+                           d["density"].astype(np.float32),
+                           d["energy"].astype(np.float32),
+                           d["time_step"],
+                           frac.astype(np.float32))
 
     plot_solution(rate, d, us)
diff --git a/src/Makefile.am b/src/Makefile.am
index 40c61f9..a77473f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 # Add the non-standard paths to the included library headers
-AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) $(GRACKLE_INCS) $(PYTHON_INCS)
+AM_CFLAGS = -I$(top_srcdir)/../src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) $(GRACKLE_INCS) $(PYTHON_INCS)
 
 # Assign a "safe" version number
 AM_LDFLAGS = $(HDF5_LDFLAGS) $(FFTW_LIBS) -version-info 0:0:0
diff --git a/src/cooling_wrapper.c b/src/cooling_wrapper.c
index 242dc7f..8def5d2 100644
--- a/src/cooling_wrapper.c
+++ b/src/cooling_wrapper.c
@@ -16,53 +16,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#include "pyswiftsim_tools.h"
 #include "cooling_wrapper.h"
-#include <omp.h>
-
 
-/**
- * @brief Initialize the cooling
- *
- * args is expecting pyswiftsim classes in the following order:
- * SwiftParams, UnitSystem and PhysConst. 
- *
- * @param self calling object
- * @param args arguments
- * @return CoolingFunctionData
- */
-PyObject* pycooling_init(PyObject* self, PyObject* args) {
-  PyObject *pyparams;
-  PyObject *pyus;
-  PyObject *pypconst;
-
-  /* parse arguments */
-  if (!PyArg_ParseTuple(args, "OOO", &pyparams, &pyus, &pypconst))
-      return NULL;
-
-  struct swift_params *params = (struct swift_params*) pytools_construct(pyparams, class_swift_params);
-  if (params == NULL)
-    return NULL;
-
-  struct unit_system *us = (struct unit_system*) pytools_construct(pyus, class_unit_system);
-  if (us == NULL)
-    return NULL;
-  
-  struct phys_const *pconst = (struct phys_const*) pytools_construct(pypconst, class_phys_const);
-  if (pconst == NULL)
-    return NULL;
-
-
-  struct cooling_function_data cooling;
-
-  /* init cooling */
-  cooling_init_backend(params, us, pconst, &cooling);
-
-  /* construct python object */
-  PyObject *pycooling = pytools_return(&cooling, class_cooling_function_data);
+/* Local includes */
+#include "pyswiftsim_tools.h"
+#include "part_wrapper.h"
 
-  return pycooling;
-}
 
 /**
  * @brief Set the cooling element fractions
@@ -117,31 +76,20 @@ void pycooling_set_fractions(struct xpart *xp, PyArrayObject* frac, const int id
 PyObject* pycooling_rate(PyObject* self, PyObject* args) {
   import_array();
   
-  PyObject *pycooling;
-  PyObject *pyus;
-  PyObject *pycosmo;
-  PyObject *pypconst;
-  PyObject *pychemistry;
+
+  char *filename;
 
   PyArrayObject *rho;
   PyArrayObject *energy;
   PyArrayObject *fractions = NULL;
 
   float dt = 1e-3;
+  int with_cosmo = 0;
 
   /* parse argument */
-  if (!PyArg_ParseTuple(args,
-			"OOOOOOO|fO",
-			&pypconst,
-			&pyus,
-			&pycosmo,
-			&pycooling,
-			&pychemistry,
-			&rho,
-			&energy,
-			&dt,
-			&fractions
-			))
+  if (!PyArg_ParseTuple(
+        args, "siOO|fO", &filename, &with_cosmo,
+	&rho, &energy, &dt, &fractions))
     return NULL;
 
   /* check numpy array */
@@ -164,37 +112,41 @@ PyObject* pycooling_rate(PyObject* self, PyObject* args) {
 
   size_t N = PyArray_DIM(energy, 0);
 
-  /* transform PyObject to C struct */
 
-  struct cooling_function_data *cooling = (struct cooling_function_data*) pytools_construct(pycooling, class_cooling_function_data);
-  if (cooling == NULL)
-    return NULL;
+  /* Initialize everything */
+  struct swift_params params;
+  parser_read_file(filename, &params);
 
-  struct unit_system *us = (struct unit_system*) pytools_construct(pyus, class_unit_system);
-  if (us == NULL)
-    return NULL;
+  struct unit_system us;
+  units_init_from_params(&us, &params, "InternalUnitSystem");
 
-  struct phys_const *pconst = (struct phys_const*) pytools_construct(pypconst, class_phys_const);
-  if (pconst == NULL)
-    return NULL;
+  struct phys_const pconst;
+  phys_const_init(&us, &params, &pconst);
 
-  struct chemistry_global_data *chemistry = (struct chemistry_global_data*) pytools_construct(pychemistry, class_chemistry_global_data);
-  if (chemistry == NULL)
-    return NULL;
+  struct cooling_function_data cooling;
 
-  struct cosmology *cosmo = (struct cosmology*) pytools_construct(pycosmo, class_cosmology);
-  if (cosmo == NULL)
-    return NULL;
+  /* init cooling */
+  cooling_init_backend(&params, &us, &pconst, &cooling);
+
+  struct chemistry_global_data chemistry;
+  chemistry_init_backend(&params, &us, &pconst, &chemistry);
+
+  struct cosmology cosmo;
+
+  if (with_cosmo)
+    cosmology_init(&params, &us, &pconst, &cosmo);
+  else
+    cosmology_init_no_cosmo(&cosmo);
 
   struct part p;
   struct xpart xp;
 
+  pyswift_part_set_to_zero(&p, &xp);
+  hydro_first_init_part(&p, &xp);
+    
   /* return object */
   PyArrayObject *rate = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(energy), PyArray_DIMS(energy), NPY_FLOAT);
 
-  /* Release GIL */
-  Py_BEGIN_ALLOW_THREADS;
-  
   /* loop over all particles */
   for(size_t i = 0; i < N; i++)
     {
@@ -206,159 +158,22 @@ PyObject* pycooling_rate(PyObject* self, PyObject* args) {
       if (fractions != NULL)
 	pycooling_set_fractions(&xp, fractions, i);
       else
-	cooling_first_init_part(pconst, us, cosmo, cooling, &p, &xp);
+	cooling_first_init_part(&pconst, &us, &cosmo, &cooling, &p, &xp);
 
-      chemistry_first_init_part(pconst, us, cosmo, chemistry, &p, &xp);
+      chemistry_first_init_part(&pconst, &us, &cosmo, &chemistry, &p, &xp);
 	
       /* compute cooling rate */
 #ifdef COOLING_GRACKLE
       float *tmp = PyArray_GETPTR1(rate, i);
-      *tmp = cooling_new_energy(pconst, us, cosmo, cooling, &p, &xp, dt);
-      *tmp = *tmp - hydro_get_physical_internal_energy(&p, &xp, cosmo);
+      *tmp = cooling_new_energy(&pconst, &us, &cosmo, &cooling, &p, &xp, dt);
+      *tmp = *tmp - hydro_get_physical_internal_energy(&p, &xp, &cosmo);
       *tmp /= dt;
-      message("%g", *tmp);
 #else
       message("Not implemented");
       //*tmp = cooling_rate(pconst, us, cosmo, cooling, &p, &xp);
 #endif
     }
 
-  /* Acquire GIL */
-  Py_END_ALLOW_THREADS;
-
   return (PyObject *) rate;
   
 }
-
-
-/**
- * @brief Compute cooling
- *
- * args is expecting pyswiftsim classes in the following order: 
- * PhysConst, UnitSystem, Cosmology and CoolingFunctionData.
- * Then two numpy arrays (density and specific energy) and a
- * float for the time step
- *
- * @param self calling object
- * @param args arguments
- * @return New energy
- */
-PyObject* pycooling_do_cooling(PyObject* self, PyObject* args) {
-  import_array();
-  
-  PyObject *pycooling;
-  PyObject *pyus;
-  PyObject *pycosmo;
-  PyObject *pypconst;
-  PyObject *pychemistry;
-
-  PyArrayObject *rho;
-  PyArrayObject *energy;
-  PyArrayObject *fractions = NULL;
-
-  float dt = 1e-3;
-
-  /* parse argument */
-  if (!PyArg_ParseTuple(args,
-			"OOOOOOOf|O",
-			&pypconst,
-			&pyus,
-			&pycosmo,
-			&pycooling,
-			&pychemistry,
-			&rho,
-			&energy,
-			&dt,
-			&fractions
-			))
-    return NULL;
-
-  /* check numpy array */
-  if (pytools_check_array(energy, 1, NPY_FLOAT, "Energy") != SUCCESS)
-    return NULL;
-
-  if (pytools_check_array(rho, 1, NPY_FLOAT, "Density") != SUCCESS)
-    return NULL;
-
-  if (fractions != NULL &&
-      pytools_check_array(fractions, 2, NPY_FLOAT, "Fractions") != SUCCESS)
-    return NULL;
-
-  if (PyArray_DIM(energy, 0) != PyArray_DIM(rho, 0))
-    pyerror("Density and energy should have the same dimension");
-
-  if (fractions != NULL &&
-      PyArray_DIM(fractions, 0) != PyArray_DIM(rho,0))
-    pyerror("Fractions should have the same first dimension than the others");
-
-  size_t N = PyArray_DIM(energy, 0);
-
-  /* transform PyObject to C struct */
-
-  struct cooling_function_data *cooling = (struct cooling_function_data*) pytools_construct(pycooling, class_cooling_function_data);
-  if (cooling == NULL)
-    return NULL;
-
-  struct unit_system *us = (struct unit_system*) pytools_construct(pyus, class_unit_system);
-  if (us == NULL)
-    return NULL;
-
-  struct phys_const *pconst = (struct phys_const*) pytools_construct(pypconst, class_phys_const);
-  if (pconst == NULL)
-    return NULL;
-
-  struct chemistry_global_data *chemistry = (struct chemistry_global_data*) pytools_construct(pychemistry, class_chemistry_global_data);
-  if (chemistry == NULL)
-    return NULL;
-
-  struct cosmology *cosmo = (struct cosmology*) pytools_construct(pycosmo, class_cosmology);
-  if (cosmo == NULL)
-    return NULL;
-
-  struct part p;
-  struct xpart xp;
-
-#ifdef COOLING_GRACKLE
-  /* set grackle_data */
-  grackle_data = &cooling->chemistry;
-#endif
-
-  /* return object */
-  PyArrayObject *new_energy = (PyArrayObject *)PyArray_SimpleNew(PyArray_NDIM(energy), PyArray_DIMS(energy), NPY_FLOAT);
-
-  /* Release GIL */
-  Py_BEGIN_ALLOW_THREADS;
-  
-  /* loop over all particles */
-  for(size_t i = 0; i < N; i++)
-    {
-      /* set particle data */
-      p.rho = *(float*) PyArray_GETPTR1(rho, i);
-      float u = *(float*) PyArray_GETPTR1(energy, i);
-      p.entropy = gas_entropy_from_internal_energy(p.rho, u);
-
-      /* initialize fields */
-      //hydro_set_internal_energy_dt(&p, 0.);
-      
-      chemistry_first_init_part(pconst, us, cosmo, chemistry, &p, &xp);
-
-      if (fractions != NULL)
-	pycooling_set_fractions(&xp, fractions, i);
-      else
-	cooling_first_init_part(pconst, us, cosmo, cooling, &p, &xp);
-      
-      /* compute cooling */
-      cooling_cool_part(pconst, us, cosmo, NULL, cooling, &p, &xp, dt, dt);
-      message("Need to redo");
-
-      /* update energy */
-      float *tmp = PyArray_GETPTR1(new_energy, i);
-      *tmp = u + dt * hydro_get_physical_internal_energy_dt(&p, NULL);
-    }
-
-  /* Acquire GIL */
-  Py_END_ALLOW_THREADS;
-
-  return (PyObject *) new_energy;
-  
-}
diff --git a/src/cooling_wrapper.h b/src/cooling_wrapper.h
index e80cb1c..a9eeeb4 100644
--- a/src/cooling_wrapper.h
+++ b/src/cooling_wrapper.h
@@ -21,11 +21,7 @@
 
 #include "pyswiftsim_tools.h"
 
-PyObject* pycooling_init(PyObject* self, PyObject* args);
-
 PyObject* pycooling_rate(PyObject* self, PyObject* args);
 
-PyObject* pycooling_do_cooling(PyObject* self, PyObject* args);
-
 #endif // __PYSWIFTSIM_COOLING_H__
 
diff --git a/src/part_wrapper.c b/src/part_wrapper.c
index 65ceec2..d8cefd8 100644
--- a/src/part_wrapper.c
+++ b/src/part_wrapper.c
@@ -22,34 +22,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-PyObject* pypart_test_struct(PyObject *self, PyObject *args)
-{
-
-  size_t N = sizeof(struct part);
-
-  /* initialize particle */
-  struct part *p = malloc(N);
-  p->id = 0;
-  for(size_t k = 0; k < DIM; k++)
-    {
-      p->x[k] = 1. + k;
-      p->v[k] = 4. + k;
-      p->a_hydro[k] = 7. + k;
-    }
-
-  p->h = 10;
-  p->mass = 11.;
-  p->rho = 12.;
-  p->entropy = 13;
-  p->entropy_dt = 14;
-  
-  hydro_init_part(p, NULL);
-
-  /* create python object */
-  PyObject *object = pytools_return(p, class_part);
-
-  free(p);
-  
-  return object;
+void pyswift_part_set_to_zero(struct part *p, struct xpart *xp) {
+  p->v[0] = 0;
+  p->v[1] = 0;
+  p->v[2] = 0;
+  p->entropy = 0;
 }
-
diff --git a/src/part_wrapper.h b/src/part_wrapper.h
index 05a2fd8..bdc3d52 100644
--- a/src/part_wrapper.h
+++ b/src/part_wrapper.h
@@ -20,16 +20,8 @@
 #define __PYSWIFTSIM_PART_H__
 
 #include <Python.h>
+#include "pyswiftsim_tools.h"
 
-/**
- * @brief Test function for the struct
- *
- * args is expecting no argument. 
- *
- * @param self calling object
- * @param args arguments
- * @return Part
- */
-PyObject* pypart_test_struct(PyObject *self, PyObject *args);
-
+void pyswift_part_set_to_zero(struct part *p, struct xpart *xp);
+  
 #endif // __PYSWIFTSIM_PART_H__
diff --git a/src/pyswiftsim.h b/src/pyswiftsim.h
new file mode 100644
index 0000000..f215e81
--- /dev/null
+++ b/src/pyswiftsim.h
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * This file is part of PYSWIFTSIM.
+ * Copyright (c) 2018 loic hausammann (loic.hausammann@epfl.ch)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+#ifndef __PYSWIFTSIM_H__
+#define __PYSWIFTSIM_H__
+
+#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+
+#include <Python.h>
+#include <numpy/arrayobject.h>
+
+/* Assert is already defined in Python.h */
+#undef assert
+#include "swift.h"
+
+
+#endif // __PYSWIFTSIM_H__
diff --git a/src/pyswiftsim_tools.h b/src/pyswiftsim_tools.h
index ca2b0d0..3cc461c 100644
--- a/src/pyswiftsim_tools.h
+++ b/src/pyswiftsim_tools.h
@@ -19,14 +19,7 @@
 #ifndef __PYSWIFTSIM_TOOLS_H__
 #define __PYSWIFTSIM_TOOLS_H__
 
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-
-#include <Python.h>
-#include <numpy/arrayobject.h>
-
-#undef assert
-#include "../config.h"
-#include "swift.h"
+#include "pyswiftsim.h"
 
 #define DIM 3
 #define STRING_SIZE 200
diff --git a/src/wrapper.c b/src/wrapper.c
index 2bc1f5f..65dbad5 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -23,7 +23,6 @@
 #include "cosmology_wrapper.h"
 #include "chemistry_wrapper.h"
 #include "pyswiftsim_tools.h"
-#include "swift.h"
 
 #include <Python.h>
 #include <math.h>
@@ -40,9 +39,6 @@ static PyMethodDef wrapper_methods[] = {
   {"unitSystemInit", pyunit_system_init, METH_VARARGS,
    "Construct a unit_system object and return it."},
 
-  {"coolingInit", pycooling_init, METH_VARARGS,
-   "Initialize cooling."},
-
   {"chemistryInit", pychemistry_init, METH_VARARGS,
    "Initialize chemistry."},
 
@@ -70,26 +66,6 @@ static PyMethodDef wrapper_methods[] = {
    "\t Cooling rate\n"
   },
 
-  {"doCooling", pycooling_do_cooling, METH_VARARGS,
-   "Compute the cooling.\n\n"
-   "Parameters\n"
-   "----------\n\n"
-   "pyconst: swift physical constant\n"
-   "pyus: swift unit system\n"
-   "cooling: swift cooling structure\n"
-   "rho: np.array\n"
-   "\t Mass density in pyus units\n"
-   "energy: np.array\n"
-   "\t Internal energy in pyus units\n"
-   "dt: float\n"
-   "\t Time step in pyus units\n"
-   "fractions: np.array, optional\n"
-   "\t Fraction of each cooling element (including metals)\n"
-   "Returns\n"
-   "-------\n\n"
-   "new_energy: np.array\n"
-   "\t Energy of the particle after dt\n"
-  },
 
   {NULL, NULL, 0, NULL}        /* Sentinel */
 };      
-- 
GitLab