From 162ea07d67d2ee55ebf8c190c58e22bb0a81ac2d Mon Sep 17 00:00:00 2001
From: Bert Vandenbroucke <bert.vandenbroucke@ugent.be>
Date: Thu, 11 Aug 2016 10:50:01 +0100
Subject: [PATCH] Added test to check if gradients are calculated correctly.

---
 .gitignore                                |   1 +
 examples/Gradients/gradientsCartesian.yml |  36 +++++
 examples/Gradients/gradientsRandom.yml    |  36 +++++
 examples/Gradients/gradientsStretched.yml |  36 +++++
 examples/Gradients/makeICs.py             | 177 ++++++++++++++++++++++
 examples/Gradients/plot.py                |  50 ++++++
 examples/Gradients/run.sh                 |  13 ++
 src/hydro/Gizmo/hydro_io.h                |   4 +-
 8 files changed, 352 insertions(+), 1 deletion(-)
 create mode 100644 examples/Gradients/gradientsCartesian.yml
 create mode 100644 examples/Gradients/gradientsRandom.yml
 create mode 100644 examples/Gradients/gradientsStretched.yml
 create mode 100644 examples/Gradients/makeICs.py
 create mode 100644 examples/Gradients/plot.py
 create mode 100755 examples/Gradients/run.sh

diff --git a/.gitignore b/.gitignore
index 9db2947d28..cb69bc5eff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ examples/*/*/*.xmf
 examples/*/*/*.hdf5
 examples/*/*/*.txt
 examples/*/*/used_parameters.yml
+examples/*/*.png
 
 tests/testPair
 tests/brute_force_standard.dat
diff --git a/examples/Gradients/gradientsCartesian.yml b/examples/Gradients/gradientsCartesian.yml
new file mode 100644
index 0000000000..917a480300
--- /dev/null
+++ b/examples/Gradients/gradientsCartesian.yml
@@ -0,0 +1,36 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1   # Grams
+  UnitLength_in_cgs:   1   # Centimeters
+  UnitVelocity_in_cgs: 1   # Centimeters per second
+  UnitCurrent_in_cgs:  1   # Amperes
+  UnitTemp_in_cgs:     1   # Kelvin
+
+# Parameters governing the time integration
+TimeIntegration:
+  time_begin: 0.    # The starting time of the simulation (in internal units).
+  time_end:   1e-6    # The end time of the simulation (in internal units).
+  dt_min:     1e-6  # The minimal time-step size of the simulation (in internal units).
+  dt_max:     1e-6  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            gradients_cartesian # Common part of the name of output files
+  time_first:          0.  # Time of the first output (in internal units)
+  delta_time:          5e-7 # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:          1e-6 # Time between statistics output
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  delta_neighbours:      0.1      # The tolerance for the targetted number of neighbours.
+  max_smoothing_length:  0.01     # Maximal smoothing length allowed (in internal units).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./Gradients_cartesian.hdf5       # The file to read
+
diff --git a/examples/Gradients/gradientsRandom.yml b/examples/Gradients/gradientsRandom.yml
new file mode 100644
index 0000000000..209f30060f
--- /dev/null
+++ b/examples/Gradients/gradientsRandom.yml
@@ -0,0 +1,36 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1   # Grams
+  UnitLength_in_cgs:   1   # Centimeters
+  UnitVelocity_in_cgs: 1   # Centimeters per second
+  UnitCurrent_in_cgs:  1   # Amperes
+  UnitTemp_in_cgs:     1   # Kelvin
+
+# Parameters governing the time integration
+TimeIntegration:
+  time_begin: 0.    # The starting time of the simulation (in internal units).
+  time_end:   1e-6    # The end time of the simulation (in internal units).
+  dt_min:     1e-6  # The minimal time-step size of the simulation (in internal units).
+  dt_max:     1e-6  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            gradients_random # Common part of the name of output files
+  time_first:          0.  # Time of the first output (in internal units)
+  delta_time:          5e-7 # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:          1e-6 # Time between statistics output
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  delta_neighbours:      0.1      # The tolerance for the targetted number of neighbours.
+  max_smoothing_length:  0.01     # Maximal smoothing length allowed (in internal units).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./Gradients_random.hdf5       # The file to read
+
diff --git a/examples/Gradients/gradientsStretched.yml b/examples/Gradients/gradientsStretched.yml
new file mode 100644
index 0000000000..592a707629
--- /dev/null
+++ b/examples/Gradients/gradientsStretched.yml
@@ -0,0 +1,36 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1   # Grams
+  UnitLength_in_cgs:   1   # Centimeters
+  UnitVelocity_in_cgs: 1   # Centimeters per second
+  UnitCurrent_in_cgs:  1   # Amperes
+  UnitTemp_in_cgs:     1   # Kelvin
+
+# Parameters governing the time integration
+TimeIntegration:
+  time_begin: 0.    # The starting time of the simulation (in internal units).
+  time_end:   1e-6    # The end time of the simulation (in internal units).
+  dt_min:     1e-6  # The minimal time-step size of the simulation (in internal units).
+  dt_max:     1e-6  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            gradients_stretched # Common part of the name of output files
+  time_first:          0.  # Time of the first output (in internal units)
+  delta_time:          5e-7 # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:          1e-6 # Time between statistics output
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  delta_neighbours:      0.1      # The tolerance for the targetted number of neighbours.
+  max_smoothing_length:  0.01     # Maximal smoothing length allowed (in internal units).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./Gradients_stretched.hdf5       # The file to read
+
diff --git a/examples/Gradients/makeICs.py b/examples/Gradients/makeICs.py
new file mode 100644
index 0000000000..38d035d2ad
--- /dev/null
+++ b/examples/Gradients/makeICs.py
@@ -0,0 +1,177 @@
+################################################################################
+# This file is part of SWIFT.
+# Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+#
+# 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/>.
+#
+################################################################################
+
+import h5py
+import random
+import numpy as np
+import sys
+
+# Generates a swift IC file with some density gradients, to check the gradient
+# reconstruction
+
+# Parameters
+periodic= 1      # 1 For periodic box
+gamma = 5./3.     # Gas adiabatic index
+gridtype = "cartesian"
+if len(sys.argv) > 1:
+    gridtype = sys.argv[1]
+
+# stretched cartesian box ######################################################
+if gridtype == "stretched":
+    fileName = "Gradients_stretched.hdf5"
+    factor = 8
+    boxSize = [ 1.0 , 1.0/factor , 1.0/factor ]
+    L = 20
+    nx1 = factor*L/2
+    ny1 = L
+    nz1 = L
+    numfac = 2.
+    nx2 = int(nx1/numfac)
+    ny2 = int(ny1/numfac)
+    nz2 = int(nz1/numfac)
+    npart = nx1*ny1*nz1 + nx2*ny2*nz2
+    vol = boxSize[0] * boxSize[1] * boxSize[2]
+    partVol1 = 0.5*vol/(nx1*ny1*nz1)
+    partVol2 = 0.5*vol/(nx2*ny2*nz2)
+
+    coords = np.zeros((npart,3))
+    h = np.zeros((npart,1))
+    ids = np.zeros((npart,1), dtype='L')
+    idx = 0
+    dcell = 0.5/nx1
+    for i in range(nx1):
+        for j in range(ny1):
+            for k in range(nz1):
+                coords[idx,0] = (i+0.5)*dcell
+                coords[idx,1] = (j+0.5)*dcell
+                coords[idx,2] = (k+0.5)*dcell
+                h[idx] = 0.56/nx1
+                ids[idx] = idx
+                idx += 1
+    dcell = 0.5/nx2
+    for i in range(nx2):
+        for j in range(ny2):
+            for k in range(nz2):
+                coords[idx,0] = 0.5+(i+0.5)*dcell
+                coords[idx,1] = (j+0.5)*dcell
+                coords[idx,2] = (k+0.5)*dcell
+                h[idx] = 0.56/nx2
+                ids[idx] = idx
+                idx += 1
+
+# cartesian box ################################################################
+if gridtype == "cartesian":
+    fileName = "Gradients_cartesian.hdf5"
+    boxSize = [ 1.0 , 1.0 , 1.0 ]
+    nx = 20
+    npart = nx**3
+    partVol = 1./npart
+    coords = np.zeros((npart,3))
+    h = np.zeros((npart,1))
+    ids = np.zeros((npart,1), dtype='L')
+    idx = 0
+    dcell = 1./nx
+    for i in range(nx):
+        for j in range(nx):
+            for k in range(nx):
+                coords[idx,0] = (i+0.5)*dcell
+                coords[idx,1] = (j+0.5)*dcell
+                coords[idx,2] = (k+0.5)*dcell
+                h[idx] = 1.12/nx
+                ids[idx] = idx
+                idx += 1
+
+# random box ###################################################################
+if gridtype == "random":
+    fileName = "Gradients_random.hdf5"
+    boxSize = [ 1.0 , 1.0 , 1.0 ]
+    glass = h5py.File("../Glass/glass_50000.hdf5", "r")
+    coords = np.array(glass["/PartType0/Coordinates"])
+    npart = len(coords)
+    partVol = 1./npart
+    h = np.zeros((npart,1))
+    ids = np.zeros((npart,1), dtype='L')
+    for i in range(npart):
+        h[i] = 0.019
+        ids[i] = i
+
+v = np.zeros((npart,3))
+m = np.zeros((npart,1))
+rho = np.zeros((npart,1))
+u = np.zeros((npart,1))
+
+for i in range(npart):
+    rhox = coords[i,0]
+    if coords[i,0] < 0.75:
+        rhox = 0.75
+    if coords[i,0] < 0.25:
+        rhox = 1.-coords[i,0]
+    rhoy = 1.+boxSize[1]-coords[i,1]
+    if coords[i,1] < 0.75*boxSize[1]:
+        rhoy = 1. + 0.25*boxSize[1]
+    if coords[i,1] < 0.25*boxSize[1]:
+        rhoy = 1.+coords[i,1]
+    rhoz = 1.
+    rho[i] = rhox + rhoy + rhoz
+    P = 1.
+    u[i] = P / ((gamma-1.)*rho[i])
+    if gridtype == "stretched":
+        if coords[i,0] < 0.5:
+            m[i] = rho[i] * partVol1
+        else:
+            m[i] = rho[i] * partVol2
+    else:
+        m[i] = rho[i] * partVol
+
+#File
+file = h5py.File(fileName, 'w')
+
+# Header
+grp = file.create_group("/Header")
+grp.attrs["BoxSize"] = boxSize
+grp.attrs["NumPart_Total"] =  [npart, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_ThisFile"] = [npart, 0, 0, 0, 0, 0]
+grp.attrs["Time"] = 0.0
+grp.attrs["NumFilesPerSnapshot"] = 1
+grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0]
+
+#Runtime parameters
+grp = file.create_group("/RuntimePars")
+grp.attrs["PeriodicBoundariesOn"] = periodic
+
+#Particle group
+grp = file.create_group("/PartType0")
+ds = grp.create_dataset('Coordinates', (npart, 3), 'd')
+ds[()] = coords
+ds = grp.create_dataset('Velocities', (npart, 3), 'f')
+ds[()] = v
+ds = grp.create_dataset('Masses', (npart,1), 'f')
+ds[()] = m
+ds = grp.create_dataset('Density', (npart,1), 'd')
+ds[()] = rho
+ds = grp.create_dataset('SmoothingLength', (npart,1), 'f')
+ds[()] = h
+ds = grp.create_dataset('InternalEnergy', (npart,1), 'd')
+ds[()] = u
+ds = grp.create_dataset('ParticleIDs', (npart,1), 'L')
+ds[()] = ids[:]
+
+file.close()
diff --git a/examples/Gradients/plot.py b/examples/Gradients/plot.py
new file mode 100644
index 0000000000..d6750ffc58
--- /dev/null
+++ b/examples/Gradients/plot.py
@@ -0,0 +1,50 @@
+################################################################################
+# This file is part of SWIFT.
+# Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+#
+# 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/>.
+#
+################################################################################
+
+import scipy as sp
+import pylab as pl
+import numpy as np
+import h5py
+import sys
+
+# this file plots the gradients of the density in the x and y direction for
+# the given input file and saves the result as gradiens_NAME.png
+
+inputfile = sys.argv[1]
+outputfile = "gradients_{0}.png".format(sys.argv[2])
+
+f = h5py.File(inputfile, "r")
+rho = np.array(f["/PartType0/Density"])
+gradrho = np.array(f["/PartType0/GradDensity"])
+coords = np.array(f["/PartType0/Coordinates"])
+
+fig, ax = pl.subplots(1,2, sharey=True)
+
+ax[0].plot(coords[:,0], rho, "r.", label="density")
+ax[0].plot(coords[:,0], gradrho[:,0], "b.", label="grad density x")
+ax[0].set_xlabel("x")
+ax[0].legend(loc="best")
+
+ax[1].plot(coords[:,1], rho, "r.", label="density")
+ax[1].plot(coords[:,1], gradrho[:,1], "b.", label="grad density y")
+ax[1].set_xlabel("y")
+ax[1].legend(loc="best")
+
+pl.tight_layout()
+pl.savefig(outputfile)
diff --git a/examples/Gradients/run.sh b/examples/Gradients/run.sh
new file mode 100755
index 0000000000..cc1adc6764
--- /dev/null
+++ b/examples/Gradients/run.sh
@@ -0,0 +1,13 @@
+#! /bin/bash
+
+python makeICs.py stretched
+../swift -s -t 2 gradientsStretched.yml
+python plot.py gradients_stretched_001.hdf5 stretched
+
+python makeICs.py cartesian
+../swift -s -t 2 gradientsCartesian.yml
+python plot.py gradients_cartesian_001.hdf5 cartesian
+
+python makeICs.py random
+../swift -s -t 2 gradientsRandom.yml
+python plot.py gradients_random_001.hdf5 random
diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h
index 4b7150050e..bba7b5e6b9 100644
--- a/src/hydro/Gizmo/hydro_io.h
+++ b/src/hydro/Gizmo/hydro_io.h
@@ -66,7 +66,7 @@ float convert_u(struct engine* e, struct part* p) {
 void hydro_write_particles(struct part* parts, struct io_props* list,
                            int* num_fields) {
 
-  *num_fields = 9;
+  *num_fields = 10;
 
   /* List what we want to write */
   list[0] = io_make_output_field("Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH,
@@ -88,6 +88,8 @@ void hydro_write_particles(struct part* parts, struct io_props* list,
                                  primitives.rho);
   list[8] = io_make_output_field("Volume", FLOAT, 1, UNIT_CONV_VOLUME, parts,
                                  geometry.volume);
+  list[9] = io_make_output_field("GradDensity", FLOAT, 3, UNIT_CONV_DENSITY,
+                                 parts, primitives.gradients.rho);
 }
 
 /**
-- 
GitLab