/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2016 Matthieu Schaller (schaller@strw.leidenuniv.nl).
*
* 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 .
*
******************************************************************************/
#ifndef SWIFT_DIMENSION_H
#define SWIFT_DIMENSION_H
/**
* @file dimension.h
* @brief Defines the dimensionality \f$d\f$ of the problem and (fast)
* mathematical functions involving it
*/
/* Config parameters. */
#include
/* Local headers. */
#include "inline.h"
#include "vector.h"
#include
/* First define some constants */
#if defined(HYDRO_DIMENSION_3D)
#define hydro_dimension 3.f
#define hydro_dimension_inv 0.3333333333f
#define hydro_dimension_unit_sphere ((float)(4. * M_PI / 3.))
#define hydro_dimension_unit_sphere_inv ((float)(3. * M_1_PI / 4.))
#elif defined(HYDRO_DIMENSION_2D)
#define hydro_dimension 2.f
#define hydro_dimension_inv 0.5f
#define hydro_dimension_unit_sphere ((float)M_PI)
#define hydro_dimension_unit_sphere_inv ((float)M_1_PI)
#elif defined(HYDRO_DIMENSION_1D)
#define hydro_dimension 1.f
#define hydro_dimension_inv 1.f
#define hydro_dimension_unit_sphere 2.f
#define hydro_dimension_unit_sphere_inv 0.5f
#else
#error "A problem dimensionality must be chosen in config.h !"
#endif
/**
* @brief Returns the argument to the power given by the dimension
*
* Computes \f$x^d\f$.
*/
__attribute__((always_inline)) INLINE static float pow_dimension(float x) {
#if defined(HYDRO_DIMENSION_3D)
return x * x * x;
#elif defined(HYDRO_DIMENSION_2D)
return x * x;
#elif defined(HYDRO_DIMENSION_1D)
return x;
#else
error("The dimension is not defined !");
return 0.f;
#endif
}
/**
* @brief Returns the argument to the power given by the inverse of the
* dimension
*
* Computes \f$x^{1/d}\f$.
*/
__attribute__((always_inline)) INLINE static float pow_inv_dimension(float x) {
#if defined(HYDRO_DIMENSION_3D)
return cbrtf(x);
#elif defined(HYDRO_DIMENSION_2D)
return sqrtf(x);
#elif defined(HYDRO_DIMENSION_1D)
return x;
#else
error("The dimension is not defined !");
return 0.f;
#endif
}
/**
* @brief Returns the argument to the power given by the dimension plus one
*
* Computes \f$x^{d+1}\f$.
*/
__attribute__((always_inline)) INLINE static float pow_dimension_plus_one(
float x) {
#if defined(HYDRO_DIMENSION_3D)
const float x2 = x * x;
return x2 * x2;
#elif defined(HYDRO_DIMENSION_2D)
return x * x * x;
#elif defined(HYDRO_DIMENSION_1D)
return x * x;
#else
error("The dimension is not defined !");
return 0.f;
#endif
}
/**
* @brief Returns the argument to the power given by the dimension minus one
*
* Computes \f$x^{d-1}\f$.
*/
__attribute__((always_inline)) INLINE static float pow_dimension_minus_one(
float x) {
#if defined(HYDRO_DIMENSION_3D)
return x * x;
#elif defined(HYDRO_DIMENSION_2D)
return x;
#elif defined(HYDRO_DIMENSION_1D)
return 1.f;
#else
error("The dimension is not defined !");
return 0.f;
#endif
}
/**
* @brief Inverts the given dimension by dimension matrix (in place)
*
* @param A A 3x3 matrix of which we want to invert the top left dxd part
* @return Exit code: 0 for success, 1 if a singular matrix was detected.
*/
__attribute__((always_inline)) INLINE static int
invert_dimension_by_dimension_matrix(float A[3][3]) {
#if defined(HYDRO_DIMENSION_3D)
int pivot[3];
for (int i = 0; i < 3; i++) {
int imax = i;
float Smax = fabsf(A[imax][i]);
for (int j = i + 1; j < 3; j++) {
const float this_Smax = fabsf(A[j][i]);
if (this_Smax > Smax) {
Smax = this_Smax;
imax = j;
}
}
if (Smax < 1.e-8f) {
/* singular matrix. Early abort */
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
A[j][k] = 0.0f;
}
}
return 1;
}
pivot[i] = imax;
if (i != imax) {
for (int j = 0; j < 3; j++) {
const float temp = A[i][j];
A[i][j] = A[imax][j];
A[imax][j] = temp;
}
}
const float Aii_inv = 1.0f / A[i][i];
for (int j = i + 1; j < 3; j++) {
A[j][i] *= Aii_inv;
}
for (int j = i + 1; j < 3; j++) {
for (int k = i + 1; k < 3; k++) {
A[j][k] -= A[j][i] * A[i][k];
}
}
}
for (int i = 0; i < 3; i++) {
A[i][i] = 1.0f / A[i][i];
for (int j = i + 1; j < 3; j++) {
float Aij = 0.0f;
for (int k = i; k < j; k++) {
Aij -= A[i][k] * A[k][j];
}
A[i][j] = Aij / A[j][j];
}
}
float work[3];
for (int jp1 = 3; jp1 > 0; jp1--) {
const int j = jp1 - 1;
for (int i = 0; i < jp1; i++) {
work[i] = A[i][j];
}
for (int i = jp1; i < 3; i++) {
work[i] = 0.0f;
}
for (int k = jp1; k < 3; k++) {
for (int i = 0; i < 3; i++) {
work[i] -= A[i][k] * A[k][j];
}
}
for (int i = 0; i < 3; i++) {
A[i][j] = work[i];
}
}
for (int jp1 = 3; jp1 > 0; jp1--) {
const int j = jp1 - 1;
const int jp = pivot[j];
if (jp != j) {
for (int i = 0; i < 3; i++) {
const float temp = A[i][j];
A[i][j] = A[i][jp];
A[i][jp] = temp;
}
}
}
return 0;
#elif defined(HYDRO_DIMENSION_2D)
float Ainv[2][2];
const float detA = A[0][0] * A[1][1] - A[0][1] * A[1][0];
const float detAinv = (detA != 0.0f) ? 1.0f / detA : 0.0f;
Ainv[0][0] = A[1][1] * detAinv;
Ainv[0][1] = -A[0][1] * detAinv;
Ainv[1][0] = -A[1][0] * detAinv;
Ainv[1][1] = A[0][0] * detAinv;
A[0][0] = Ainv[0][0];
A[0][1] = Ainv[0][1];
A[1][0] = Ainv[1][0];
A[1][1] = Ainv[1][1];
return 0;
#elif defined(HYDRO_DIMENSION_1D)
if (A[0][0] && !isnan(A[0][0])) {
A[0][0] = 1.0f / A[0][0];
} else {
A[0][0] = 0.0f;
}
return 0;
#else
error("The dimension is not defined !");
#endif
}
/**
* @brief Get the radius of a dimension sphere with the given volume
*
* @param volume Volume of the dimension sphere
* @return Radius of the dimension sphere
*/
__attribute__((always_inline)) INLINE static float get_radius_dimension_sphere(
float volume) {
#if defined(HYDRO_DIMENSION_3D)
return cbrtf(volume * hydro_dimension_unit_sphere_inv);
#elif defined(HYDRO_DIMENSION_2D)
return sqrtf(volume * hydro_dimension_unit_sphere_inv);
#elif defined(HYDRO_DIMENSION_1D)
return volume * hydro_dimension_unit_sphere_inv;
#else
error("The dimension is not defined !");
return 0.f;
#endif
}
/* ------------------------------------------------------------------------- */
#ifdef WITH_VECTORIZATION
/**
* @brief Returns the argument to the power given by the dimension (vector
* version)
*
* Computes \f$x^d\f$.
*/
__attribute__((always_inline)) INLINE static vector pow_dimension_vec(
vector x) {
#if defined(HYDRO_DIMENSION_3D)
return (vector)(vec_mul(vec_mul(x.v, x.v), x.v));
#elif defined(HYDRO_DIMENSION_2D)
return (vector)(vec_mul(x.v, x.v));
#elif defined(HYDRO_DIMENSION_1D)
return x;
#else
error("The dimension is not defined !");
return vec_set1(0.f);
#endif
}
/**
* @brief Returns the argument to the power given by the dimension plus one
* (vector version)
*
* Computes \f$x^{d+1}\f$.
*/
__attribute__((always_inline)) INLINE static vector pow_dimension_plus_one_vec(
vector x) {
#if defined(HYDRO_DIMENSION_3D)
const vector x2 = (vector)(vec_mul(x.v, x.v));
return (vector)(vec_mul(x2.v, x2.v));
#elif defined(HYDRO_DIMENSION_2D)
return (vector)(vec_mul(x.v, vec_mul(x.v, x.v)));
#elif defined(HYDRO_DIMENSION_1D)
return (vector)(vec_mul(x.v, x.v));
#else
error("The dimension is not defined !");
return vec_set1(0.f);
#endif
}
#endif
#endif /* SWIFT_DIMENSION_H */