Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
DLR-AMR
GitHub Repository: DLR-AMR/t8code
Path: blob/main/example/common/t8_example_common_functions.cxx
901 views
/*
  This file is part of t8code.
  t8code is a C library to manage a collection (a forest) of multiple
  connected adaptive space-trees of general element types in parallel.

  Copyright (C) 2015 the developers

  t8code 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 2 of the License, or
  (at your option) any later version.

  t8code 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 t8code; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/** \file t8_example_common_functions.cxx Provide real valued functions
  * that are used in more than one example. */

#include <example/common/t8_example_common.hxx>
#include <t8_types/t8_vec.hxx>

double
t8_levelset_sphere (const t8_3D_point &x, [[maybe_unused]] const double t, void *data)
{
  t8_levelset_sphere_data_t *ls_data = (t8_levelset_sphere_data_t *) data;

  T8_ASSERT (ls_data->radius > 0);
  return t8_dist (x, ls_data->M) - ls_data->radius;
}

double
t8_scalar3d_constant_one ([[maybe_unused]] const double x[3], [[maybe_unused]] double t)
{
  return 1;
}

double
t8_scalar3d_constant_zero ([[maybe_unused]] const double x[3], [[maybe_unused]] double t)
{
  return 0;
}

double
t8_scalar3d_project_x (const double x[3], [[maybe_unused]] double t)
{
  return x[0];
}

double
t8_scalar3d_exp_distribution (const double x[3], double t)
{
  double dummy, X;

  /* Get fractional part of t. t is thus periodically
   * mapped to the unit interval */
  t = modf (t, &dummy);
  X = x[0] - .5;
  return exp (-4 * X * X);
}

/* This function is =1 if 0.25 <= x <= 0.75 and 0 else */
double
t8_scalar3d_step_function (const double x[3], [[maybe_unused]] double t)
{
  return 0.25 <= x[0] && x[0] <= 0.75;
}

/* This function is =1 if 0.25 <= x <= 0.75,
 * it is 0 outside of 0.25-eps and 0.75+eps,
 * it interpolates linearly in between. */
double
t8_scalar3d_almost_step_function (const double x[3], [[maybe_unused]] double t)
{
  double eps = 0.1;

  /* interpolate in [0.25-eps,0.25+eps] */
  if (0.25 - eps < x[0] && x[0] < 0.25) {
    return (x[0] - 0.25 + eps) / (eps);
  }
  /* interpolate in [0.75-eps,0.75+eps] */
  else if (0.75 < x[0] && x[0] < 0.75 + eps) {
    return 1 - (x[0] - 0.75) / (eps);
  }
  /* 1 inside [0.25,0.75], 0 outside */
  return 0.25 <= x[0] && x[0] <= 0.75;
}

double
t8_scalar3d_sinx (const double x[3], [[maybe_unused]] double t)
{
  return sin (2 * M_PI * x[0]) + 1;
}

double
t8_scalar3d_sinx_cosy (const double x[3], [[maybe_unused]] double t)
{
  return sin (2 * M_PI * x[0]) * cos (2 * M_PI * x[1]);
}

double
t8_scalar3d_sinx_cosy_z (const double x[3], [[maybe_unused]] double t)
{
  return 10 * sin (2 * M_PI * x[0]) * cos (2 * M_PI * x[1]) * x[3];
}

double
t8_scalar3d_sint ([[maybe_unused]] const double x[3], double t)
{
  return sin (2 * M_PI * t);
}

/* general level set function for a sphere with given midpoint and radius. */
static double
t8_scalar3d_sphere (const t8_3D_vec &x, t8_3D_vec &M, const double radius)
{

  /* Compute M - x */
  t8_axpy (x, M, -1);

  /* return |M-x| - radius */

  return t8_norm (M) - radius;
}

double
t8_scalar3d_sphere_75_radius (const t8_3D_vec x, [[maybe_unused]] const double t)
{
  t8_3D_vec M ({ 0, 0, 0 });
  return t8_scalar3d_sphere (x, M, 0.75);
}

double
t8_scalar3d_sphere_05_midpoint_375_radius (const t8_3D_vec x, [[maybe_unused]] double t)
{
  t8_3D_vec M ({ 0.5, 0.5, 0.5 });

  return t8_scalar3d_sphere (x, M, 0.375);
}

double
t8_scalar3d_sphere_03_midpoint_25_radius (const t8_3D_vec &x, [[maybe_unused]] const double t)
{
  t8_3D_vec M ({ 0.3, 0.3, 0.3 });

  return t8_scalar3d_sphere (x, M, 0.25);
}

double
t8_scalar3d_sphere_05_0z_midpoint_375_radius (const t8_3D_vec &x, [[maybe_unused]] const double t)
{
  t8_3D_vec M ({ 0.5, 0.5, 0 });

  return t8_scalar3d_sphere (x, M, 0.375);
}

void
t8_flow_constant_one_vec ([[maybe_unused]] const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  x_out[0] = x_out[1] = x_out[2] = 1;
}

void
t8_flow_constant_one_x_vec ([[maybe_unused]] const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  x_out[0] = 1;
  x_out[1] = x_out[2] = 0;
}

void
t8_flow_constant_one_xy_vec ([[maybe_unused]] const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  x_out[0] = 1;
  x_out[1] = 0.8;
  x_out[2] = 0;
}

void
t8_flow_constant_one_xyz_vec ([[maybe_unused]] const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  x_out[0] = 1;
  x_out[1] = 0.8;
  x_out[2] = 0.9;
}

void
t8_flow_rotation_2d (const t8_3D_point &x_in, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  double x = x_in[0], y = x_in[1];

  x -= 0.5;
  y -= 0.5;

  x_out[0] = y;
  x_out[1] = -x;
  x_out[2] = 0;

  t8_ax (x_out, 2 * M_PI);
}

void
t8_flow_compressible (const t8_3D_point &x_in, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  x_out[0] = (1. / 2 - x_in[0]);
  x_out[1] = 0;
  x_out[2] = 0;
}

/* The following function is a incompressible flow on the unit cube.
 * It is constructed from any function f with f(0) = f(1) = 0.
 */

static double
t8_incomp_cube_f_sin (double x)
{
  return sin (M_PI * x);
}

static double
t8_incomp_cube_df_sin (double x)
{
  return M_PI * cos (M_PI * x);
}

void
t8_flow_incomp_cube_flow (const t8_3D_point &x, const double t, t8_3D_vec &x_out)
{
  double (*f) (double) = t8_incomp_cube_f_sin;
  double (*df) (double) = t8_incomp_cube_df_sin;

  x_out[0] = f (x[0]) * (df (x[1]) - df (x[2]));
  x_out[1] = -1. * f (x[1]) * df (x[0]);
  x_out[2] = f (x[2]) * df (x[0]);

  t8_ax (x_out, 1. / 2);
  /* We reverse the flow at time 0.5 */
  if (t > 0.5) {
    t8_ax (x_out, -1);
  }
}

/* Convert the first two entries of a vector into 2D polar
 * coordinates. x = r cos(phi)
 *              y = r sin(phi)
 *
 * On output: polar[0] = r, polar[1] = phi
 */
static void
t8_flow_2d_polar_coords (const t8_vec<2> &x, t8_vec<2> &polar)
{
  polar[0] = sqrt (SC_SQR (x[0]) + SC_SQR (x[1]));
  polar[1] = atan2 (x[1], x[0]);
}

/* Convert a 2D vector from polar coordinates to cartesian
 * coordinates.
 * On input: polar[0] = r, polar[1] = phi
 *
 * On output: cart[0] = r cos(phi)
 *            cart[1] = r sin(phi)
 *
 */
static void
t8_flow_2d_cart_coords (const t8_vec<2> &polar_values, const t8_vec<2> &polar_coords, t8_vec<2> &cart)
{
  cart[0] = cos (polar_coords[1]) * polar_values[0] - sin (polar_coords[1]) * polar_values[1];
  cart[1] = sin (polar_coords[1]) * polar_values[0] + cos (polar_coords[1]) * polar_values[1];
}

/* 2d flow around a circle with radius R = 1 and
 * constant inflow with x-speed U = 1. */
void
t8_flow_around_circle (const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  t8_vec<2> polar;
  t8_vec<2> polar_speed;
  const t8_vec<2> x_2D = t8_vec<2> ({ x[0], x[1] });
  t8_vec<2> x_out_2D ({ x_out[0], x_out[1] });
  const double R = 0.15;

  t8_axb (x_2D, x_out_2D, 1, -0.5);
  /* Set the z-coordinate to zero */
  if (t8_norm (x_out) < R) {
    /* Set the velocity inside the circle to 0 */
    x_out[0] = x_out[1] = 0;
    return;
  }
  /* Convert x,y coordinates to polar r,phi coordinates */
  t8_flow_2d_polar_coords (x_out_2D, polar);
  /* Compute v_r (r,phi) = U (1-R^2/r^2)cos(phi) */
  polar_speed[0] = (1 - SC_SQR (R) / SC_SQR (polar[0])) * cos (polar[1]);
  /* Compute v_phi(r,phi) = -U (1+ R^2/r^2) sin (phi) */
  polar_speed[1] = -(1 + SC_SQR (R) / SC_SQR (polar[0])) * sin (polar[1]);
  t8_flow_2d_cart_coords (polar_speed, polar, x_out_2D);
  x_out[0] = x_out_2D[0];
  x_out[1] = x_out_2D[1];
  x_out[2] = 0;
}

/* The following functions model a solution to the stokes equation on
 * a spherical shell. See
 * Analytical solution for viscous incompressible Stokes flow in a
 * spherical shell
 * by Cedric Thieulot
 */

static void
t8_flow_stokes_sphere_alpha_beta (double R_1, double R_2, double gamma, int m, double *alpha, double *beta)
{
  /* We define two constants alpha and beta */
  *alpha = gamma * (m + 1) * (pow (R_1, -3) - pow (R_2, -3)) / (pow (R_1, -m - 4) - pow (R_2, -m - 4));
  *beta = -3 * gamma * (pow (R_1, m + 1) - pow (R_2, m + 1)) / (pow (R_1, m + 4) - pow (R_2, m + 4));
}

/* A component of the flow that depends on the inner radius R_2, the outer radius R_1,
 * a constant gamma, and a control parameter m with m != -1, m != -4 */
static double
t8_flow_stokes_sphere_g_component (double radius, double alpha, double beta, double gamma, int m)
{
  T8_ASSERT (m != -1 && m != -4);

  return -2 / (radius * radius) * (-alpha / (m + 1) * pow (radius, -m - 1) + beta / 3 * pow (radius, 3) + gamma);
}

static double
t8_flow_stokes_sphere_f_component (double radius, double alpha, double beta, int m)
{
  return alpha * pow (radius, -m - 3) + beta * radius;
}

void
t8_flow_stokes_flow_sphere_shell (const t8_3D_point &x_in, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  double radius;
  double theta, phi;
  double alpha, beta;
  double vel_r;
  double vel_theta;
  double vel_phi;
  const double r_1 = .5, r_2 = 1, gamma = 1, m = 3;
  /* translate unit cube to cube centered around origin */
  t8_3D_vec x ({ (x_in[0] - 0.5 * 2), (x_in[1] - 0.5 * 2), (x_in[2] - 0.5 * 2) });

  /* Compute spherical coordinates */
  radius = t8_norm (x);
  theta = acos (x[2] / radius);
  /* Phi component, not used */
  phi = atan2 (x[1], x[0]);

  if (radius < r_1) {
    /* If there are points in the geometry that lie in the inside radius,
     * set the flow to zero. */
    x_out[0] = x_out[1] = x_out[2] = 0;
    return;
  }

  /* Compute alpha and beta */
  t8_flow_stokes_sphere_alpha_beta (r_1, r_2, gamma, m, &alpha, &beta);
  /* Compute radial velocity and theta velocity */
  vel_r = t8_flow_stokes_sphere_g_component (radius, alpha, beta, gamma, m) * cos (theta);
  vel_theta = t8_flow_stokes_sphere_f_component (radius, alpha, beta, m) * sin (theta);
  /* Set phi velocity */
  vel_phi = 0;

  /* Compute euclidean coordinates */
  x_out[0] = vel_r * sin (theta) * cos (phi) + vel_theta * cos (theta) * cos (phi) - vel_phi * sin (phi);
  x_out[1] = vel_r * sin (theta) * sin (phi) + vel_theta * cos (theta) * sin (phi) + vel_phi * cos (phi);
  x_out[2] = vel_r * cos (theta) - vel_theta * cos (theta);
}

void
t8_flow_around_circle_with_angular_velocity (const t8_3D_point &x, [[maybe_unused]] const double t, t8_3D_vec &x_out)
{
  const double radius = 0.5;
  const double omega = 1.5 * M_PI;
  // convert to polar coordinates
  const double r = sqrt (x[0] * x[0] + x[1] * x[1]);
  const double theta = atan2 (x[1], x[0]);

  //calculate flow
  const double u_r = (1 - (radius * radius) / (r * r)) * cos (theta);
  const double u_theta = -(1 + (radius * radius) / (r * r)) * sin (theta) - omega / (2 * M_PI * r);

  // convert back to Cartesian
  x_out[0] = cos (theta) * u_r - sin (theta) * u_theta;
  x_out[1] = sin (theta) * u_r + cos (theta) * u_theta;
  x_out[2] = 0;
}