|  | @@ -0,0 +1,1097 @@
 | 
											
												
													
														|  | 
 |  | +#include <math.h>
 | 
											
												
													
														|  | 
 |  | +#include <stdlib.h>
 | 
											
												
													
														|  | 
 |  | +#include <stdio.h>
 | 
											
												
													
														|  | 
 |  | +#include <string.h>
 | 
											
												
													
														|  | 
 |  | +#include <complex.h>
 | 
											
												
													
														|  | 
 |  | +#include <omp.h>
 | 
											
												
													
														|  | 
 |  | +#include "diff_eq_system.h"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void ephi(double phi, double* vector) {
 | 
											
												
													
														|  | 
 |  | +  vector[0] = -sin(phi);
 | 
											
												
													
														|  | 
 |  | +  vector[1] = cos(phi);
 | 
											
												
													
														|  | 
 |  | +  vector[2] = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void etheta(double phi, double theta, double* vector) {
 | 
											
												
													
														|  | 
 |  | +  vector[0] = cos(phi) * cos(theta);
 | 
											
												
													
														|  | 
 |  | +  vector[1] = sin(phi) * cos(theta);
 | 
											
												
													
														|  | 
 |  | +  vector[2] = -sin(theta);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void sph_to_cart(double theta, double phi, double* cartesian) {
 | 
											
												
													
														|  | 
 |  | +  cartesian[0] = cos(phi) * sin(theta);
 | 
											
												
													
														|  | 
 |  | +  cartesian[1] = sin(phi) * sin(theta);
 | 
											
												
													
														|  | 
 |  | +  cartesian[2] = cos(theta);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void cross_product(double* vector0, double* vector1, double* result) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  result[0] = vector0[1] * vector1[2] - vector0[2] * vector1[1];
 | 
											
												
													
														|  | 
 |  | +  result[1] = vector0[2] * vector1[0] - vector0[0] * vector1[2];
 | 
											
												
													
														|  | 
 |  | +  result[2] = vector0[0] * vector1[1] - vector0[1] * vector1[0];
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void lattice_base(int n, double* thetas, double* phis, double* basis) {
 | 
											
												
													
														|  | 
 |  | +    // Returns n x 3 x 3 array of local lattice bases, serves as transformation from global to local basis
 | 
											
												
													
														|  | 
 |  | +    double cos_phi, sin_phi, cos_theta, sin_theta;
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<n; i++) {
 | 
											
												
													
														|  | 
 |  | +      cos_phi = cos(phis[i]);
 | 
											
												
													
														|  | 
 |  | +      sin_phi = sin(phis[i]);
 | 
											
												
													
														|  | 
 |  | +      cos_theta = cos(thetas[i]);
 | 
											
												
													
														|  | 
 |  | +      sin_theta = sin(thetas[i]);
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 0] = cos_phi * sin_theta;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 1] = sin_theta * sin_phi;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 2] = cos_theta;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 3] = cos_theta * cos_phi;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 4] = cos_theta * sin_phi;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 5] = -sin_theta;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 6] = -sin_phi;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 7] = cos_phi;
 | 
											
												
													
														|  | 
 |  | +      basis[9*i + 8] = 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void rodrigues_rotation(double* vec, double angle, double* axis, double* result) {
 | 
											
												
													
														|  | 
 |  | +  double cos_angle = cos(angle);
 | 
											
												
													
														|  | 
 |  | +  double sin_angle = sin(angle);
 | 
											
												
													
														|  | 
 |  | +  double scalar;
 | 
											
												
													
														|  | 
 |  | +  double cross[3];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  cross_product(axis, vec, cross);
 | 
											
												
													
														|  | 
 |  | +  scalar = axis[0]*vec[0] + axis[1]*vec[1] + axis[2]*vec[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  result[0] = vec[0] * cos_angle + cross[0] * sin_angle + axis[0] * scalar * (1 - cos_angle);
 | 
											
												
													
														|  | 
 |  | +  result[1] = vec[1] * cos_angle + cross[1] * sin_angle + axis[1] * scalar * (1 - cos_angle);
 | 
											
												
													
														|  | 
 |  | +  result[2] = vec[2] * cos_angle + cross[2] * sin_angle + axis[2] * scalar * (1 - cos_angle);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void x_to_z_transf(int n, double* vectors) {
 | 
											
												
													
														|  | 
 |  | +  // rotation of all vectors in array for pi/2 around y-axis (transformation x -> z and z -> -x)
 | 
											
												
													
														|  | 
 |  | +  double new_x;
 | 
											
												
													
														|  | 
 |  | +  double new_z;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<n;   i++) {
 | 
											
												
													
														|  | 
 |  | +    new_x = -vectors[3*i+2];
 | 
											
												
													
														|  | 
 |  | +    new_z = vectors[3*i];
 | 
											
												
													
														|  | 
 |  | +    vectors[3*i] = new_x;
 | 
											
												
													
														|  | 
 |  | +    vectors[3*i+2] = new_z;
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void inverse_x_to_z_transformation(int n, double* vectors) {
 | 
											
												
													
														|  | 
 |  | +  // rotation of all vectors in array for -pi/2 around y-axis (transformation x -> -z and z -> x)
 | 
											
												
													
														|  | 
 |  | +  double new_x;
 | 
											
												
													
														|  | 
 |  | +  double new_z;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<n;   i++) {
 | 
											
												
													
														|  | 
 |  | +    new_x = vectors[3*i+2];
 | 
											
												
													
														|  | 
 |  | +    new_z = -vectors[3*i];
 | 
											
												
													
														|  | 
 |  | +    vectors[3*i] = new_x;
 | 
											
												
													
														|  | 
 |  | +    vectors[3*i+2] = new_z;
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double complex stereogr_proj(double theta, double phi) {
 | 
											
												
													
														|  | 
 |  | +  return cexp(I * phi) / tan(theta / 2.);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void psi_avg(double* thetas, double* phis, double alpha0, double* result) {
 | 
											
												
													
														|  | 
 |  | +  // Minimizing defect orientation
 | 
											
												
													
														|  | 
 |  | +  double complex ln_sum;
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +    ln_sum = 0;
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +      if (j != i) {
 | 
											
												
													
														|  | 
 |  | +        ln_sum += clog(stereogr_proj(thetas[i], phis[i]) - stereogr_proj(thetas[j], phis[j]));
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    result[i] = phis[i] - 2 * alpha0 - cimag(ln_sum);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double cos_beta_ij(double theta_i, double phi_i, double theta_j, double phi_j) {
 | 
											
												
													
														|  | 
 |  | +  // Angular distance between defects
 | 
											
												
													
														|  | 
 |  | +  return cos(theta_i) * cos(theta_j) + sin(theta_i) * sin(theta_j) * cos(phi_i - phi_j);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double dcos_beta_dtheta(double theta_i, double phi_i, double theta_j, double phi_j) {
 | 
											
												
													
														|  | 
 |  | +  // d(cos beta_ki) / d theta_k
 | 
											
												
													
														|  | 
 |  | +  return -sin(theta_i) * cos(theta_j) + cos(theta_i) * sin(theta_j) * cos(phi_i - phi_j);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double dcos_beta_dphi(double theta_i, double phi_i, double theta_j, double phi_j) {
 | 
											
												
													
														|  | 
 |  | +  // d(cos beta_ki) / d phi_k
 | 
											
												
													
														|  | 
 |  | +  return  -sin(theta_i) * sin(theta_j) * sin(phi_i - phi_j);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double free_energy(double* thetas, double* phis, double* delta_psi, double chi) {
 | 
											
												
													
														|  | 
 |  | +  // elastic free energy
 | 
											
												
													
														|  | 
 |  | +  double en = 0;
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +    en += chi * delta_psi[i] * delta_psi[i];
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +      if (j != i) {
 | 
											
												
													
														|  | 
 |  | +        en += -clog(1 - cos_beta_ij(thetas[i], phis[i], thetas[j], phis[j]));
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return en;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double free_energy_pos(double* thetas, double* phis) {
 | 
											
												
													
														|  | 
 |  | +  // lastic free energy
 | 
											
												
													
														|  | 
 |  | +  double en = 0;
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +      if (j != i) {
 | 
											
												
													
														|  | 
 |  | +        en += -clog(1 - cos_beta_ij(thetas[i], phis[i], thetas[j], phis[j]));
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return en;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double free_energy_orient(double* delta_psi, double chi) {
 | 
											
												
													
														|  | 
 |  | +  // lastic free energy
 | 
											
												
													
														|  | 
 |  | +  double en = 0;
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +    en += chi * delta_psi[i] * delta_psi[i];
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return en;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void df_dtheta(double* thetas, double* phis, double* delta_psi, double chi, double* derivatives) {
 | 
											
												
													
														|  | 
 |  | +  // Free energy derivative over theta_k
 | 
											
												
													
														|  | 
 |  | +  for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +    derivatives[k] = 0;
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +      if (i != k) {
 | 
											
												
													
														|  | 
 |  | +        derivatives[k] += 2 * (
 | 
											
												
													
														|  | 
 |  | +                          dcos_beta_dtheta(thetas[k], phis[k], thetas[i], phis[i]) /
 | 
											
												
													
														|  | 
 |  | +                          (1 - cos_beta_ij(thetas[k], phis[k], thetas[i], phis[i])) -
 | 
											
												
													
														|  | 
 |  | +                          chi * (delta_psi[k] + delta_psi[i]) / sin(thetas[k]) *
 | 
											
												
													
														|  | 
 |  | +                          cimag(stereogr_proj(thetas[k], phis[k]) /
 | 
											
												
													
														|  | 
 |  | +                          (stereogr_proj(thetas[k], phis[k]) - stereogr_proj(thetas[i], phis[i])))
 | 
											
												
													
														|  | 
 |  | +                        );
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void df_dphi(double* thetas, double* phis, double* delta_psi, double chi, double* derivatives) {
 | 
											
												
													
														|  | 
 |  | +  // Free energy derivative over phi_k
 | 
											
												
													
														|  | 
 |  | +  for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +    derivatives[k] = 0;
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +      if (i != k) {
 | 
											
												
													
														|  | 
 |  | +        derivatives[k] += 2 * (
 | 
											
												
													
														|  | 
 |  | +                          dcos_beta_dphi(thetas[k], phis[k], thetas[i], phis[i]) /
 | 
											
												
													
														|  | 
 |  | +                          (1 - cos_beta_ij(thetas[k], phis[k], thetas[i], phis[i])) +
 | 
											
												
													
														|  | 
 |  | +                          chi * (
 | 
											
												
													
														|  | 
 |  | +                            (delta_psi[k] + delta_psi[i]) *
 | 
											
												
													
														|  | 
 |  | +                            creal(stereogr_proj(thetas[k], phis[k]) /
 | 
											
												
													
														|  | 
 |  | +                            (stereogr_proj(thetas[k], phis[k]) - stereogr_proj(thetas[i], phis[i]))) -
 | 
											
												
													
														|  | 
 |  | +                            delta_psi[k] / 3.
 | 
											
												
													
														|  | 
 |  | +                          )
 | 
											
												
													
														|  | 
 |  | +                        );
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double df_dalpha0(double* delta_psi, double chi) {
 | 
											
												
													
														|  | 
 |  | +  // Free energy derivative over alpha0
 | 
											
												
													
														|  | 
 |  | +  double derivative = 0;
 | 
											
												
													
														|  | 
 |  | +  for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +    derivative += 4 * chi * delta_psi[k];
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  return derivative;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void df_dpsi(double* delta_psi, double chi, double* derivatives) {
 | 
											
												
													
														|  | 
 |  | +  // Free energy derivative over psi_k
 | 
											
												
													
														|  | 
 |  | +  for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +    derivatives[k] = 2 * chi * delta_psi[k];
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void eq_system(double* variables, double nu, double chi, double xi_rot, double xi_alpha, double* dy_dt) {
 | 
											
												
													
														|  | 
 |  | +    // System of differential equations. y=[theta_k, phi_k, psi_k, alpha0] (len(y)=13)
 | 
											
												
													
														|  | 
 |  | +    double thetas[4];
 | 
											
												
													
														|  | 
 |  | +    double phis[4];
 | 
											
												
													
														|  | 
 |  | +    double psis[4];
 | 
											
												
													
														|  | 
 |  | +    double delta_psi[4];
 | 
											
												
													
														|  | 
 |  | +    double alpha0 = variables[12];
 | 
											
												
													
														|  | 
 |  | +    double average_psi[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    psi_avg(&variables[0], &variables[4], alpha0, average_psi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +      thetas[i] = variables[i];
 | 
											
												
													
														|  | 
 |  | +      phis[i] = variables[4 + i];
 | 
											
												
													
														|  | 
 |  | +      psis[i] = variables[8 + i];
 | 
											
												
													
														|  | 
 |  | +      delta_psi[i] = psis[i] - average_psi[i];
 | 
											
												
													
														|  | 
 |  | +      delta_psi[i] -= M_PI * (2 * floor((delta_psi[i]+M_PI) / (2 * M_PI)));  // map into the interval [-pi , pi]
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double theta_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double phi_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double psi_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double alpha0_deriv = df_dalpha0(delta_psi, chi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    df_dtheta(thetas, phis, delta_psi, 0, theta_deriv);  // chi=0 for stability
 | 
											
												
													
														|  | 
 |  | +    df_dphi(thetas, phis, delta_psi, 0, phi_deriv);  // chi=0 for stability
 | 
											
												
													
														|  | 
 |  | +    df_dpsi(delta_psi, chi, psi_deriv);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double complex compl_velocity_conj[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +      // dtheta/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[k] = -theta_deriv[k] + nu * cos(psis[k]);
 | 
											
												
													
														|  | 
 |  | +      // dphi/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[4 + k] = -phi_deriv[k] / (sin(thetas[k]) * sin(thetas[k])) + nu * sin(psis[k]) / sin(thetas[k]);
 | 
											
												
													
														|  | 
 |  | +      // dpsi/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[8 + k] = -1 / xi_rot * psi_deriv[k] - cos(thetas[k]) * dy_dt[4 + k];
 | 
											
												
													
														|  | 
 |  | +      // conjugated complex velocity
 | 
											
												
													
														|  | 
 |  | +      compl_velocity_conj[k] = dy_dt[k] - I * sin(thetas[k]) * dy_dt[4 + k];
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // dalpha0/dt
 | 
											
												
													
														|  | 
 |  | +    double inner_summand;
 | 
											
												
													
														|  | 
 |  | +    double outer_sum=0;
 | 
											
												
													
														|  | 
 |  | +    for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +      inner_summand = 0;
 | 
											
												
													
														|  | 
 |  | +      for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +        if (j != k) {
 | 
											
												
													
														|  | 
 |  | +          inner_summand += cimag( stereogr_proj(thetas[k], phis[k]) *
 | 
											
												
													
														|  | 
 |  | +                          compl_velocity_conj[k] /
 | 
											
												
													
														|  | 
 |  | +                          (stereogr_proj(thetas[k], phis[k]) - stereogr_proj(thetas[j], phis[j])) );
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      outer_sum += 1 / 8. * ( (1 + cos(thetas[k])) * dy_dt[4 + k] + 2 / sin(thetas[k]) * inner_summand );
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    dy_dt[12] = -1 / xi_alpha * alpha0_deriv + outer_sum;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void eq_system_reduced(double* variables, double nu, double tau, double* dy_dt) {
 | 
											
												
													
														|  | 
 |  | +  // System of reduced differential equations. y=[Theta, Phi, Psi, Delta_Psi, phi1] (len(y)=5)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double theta = variables[0];
 | 
											
												
													
														|  | 
 |  | +  double phi = variables[1];
 | 
											
												
													
														|  | 
 |  | +  double avg_psi = variables[2];
 | 
											
												
													
														|  | 
 |  | +  double delta_psi = variables[3]; // - M_PI * (2 * floor((variables[3] + M_PI) / (2 * M_PI)));
 | 
											
												
													
														|  | 
 |  | +  double phi1 = variables[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double sin_theta = sin(theta);
 | 
											
												
													
														|  | 
 |  | +  double cos_theta = cos(theta);
 | 
											
												
													
														|  | 
 |  | +  double tan_theta = tan(theta);
 | 
											
												
													
														|  | 
 |  | +  double sin_phi = sin(phi);
 | 
											
												
													
														|  | 
 |  | +  double cos_phi = cos(phi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // dtheta/dt
 | 
											
												
													
														|  | 
 |  | +  dy_dt[0] = nu * cos(avg_psi + delta_psi) + 2 * (4 - 8 * pow(sin_theta, 2) + 3 * pow(sin_theta, 4) * pow(sin_phi, 2)) /
 | 
											
												
													
														|  | 
 |  | +            (tan_theta * ((1 + pow(cos_theta, 2)) * (1 + pow(cos_theta, 2)) - pow(sin_theta, 4) * pow(cos_phi, 2)));
 | 
											
												
													
														|  | 
 |  | +  // dphi/dt
 | 
											
												
													
														|  | 
 |  | +  dy_dt[1] = -2 * nu * sin(avg_psi) * cos(delta_psi) / sin_theta + 8 * pow(sin_theta, 2) * sin_phi * cos_phi /
 | 
											
												
													
														|  | 
 |  | +            ((1 + pow(cos_theta, 2)) * (1 + pow(cos_theta, 2)) - pow(sin_theta, 4) * pow(cos_phi, 2));
 | 
											
												
													
														|  | 
 |  | +  // d(avg_psi)/dt
 | 
											
												
													
														|  | 
 |  | +  dy_dt[2] = cos_theta / 2 * dy_dt[1];
 | 
											
												
													
														|  | 
 |  | +  // d(delta_psi)/dt
 | 
											
												
													
														|  | 
 |  | +  dy_dt[3] = -nu * cos(avg_psi) * sin(delta_psi) / tan_theta - delta_psi / tau;
 | 
											
												
													
														|  | 
 |  | +  // dphi1/dt
 | 
											
												
													
														|  | 
 |  | +  dy_dt[4] = nu / sin_theta * cos(avg_psi) * sin(delta_psi) - dy_dt[1] / 2;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_trajectories_block(double* variables, double nu, double chi, double xi_rot, double xi_alpha,
 | 
											
												
													
														|  | 
 |  | +  double dt, int num_steps) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double k1[13];
 | 
											
												
													
														|  | 
 |  | +  double k2[13];
 | 
											
												
													
														|  | 
 |  | +  double intermed[13];
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<num_steps; i++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    eq_system(variables, nu, chi, xi_rot, xi_alpha, k1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +      intermed[j] = variables[j] + 2. / 3. * dt * k1[j];
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    eq_system(intermed, nu, chi, xi_rot, xi_alpha, k2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +      variables[j] = variables[j] + dt * (1.0 / 4.0) * (k1[j] + 3 * k2[j]);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_trajectories(double* variables0, double nu, double chi, double xi_rot, double xi_alpha,
 | 
											
												
													
														|  | 
 |  | +                            double t_span, double dt, int num_save,
 | 
											
												
													
														|  | 
 |  | +                            double* results, double* timepoints, int* nfev) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Should be len(results) / 13 = len(timepoints) = num_save
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +  int save_interval = round(t_span / (dt * (num_save - 1)));
 | 
											
												
													
														|  | 
 |  | +  dt = t_span / (save_interval * (num_save - 1));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  nfev[0] = 2 * save_interval * (num_save - 1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<num_save; i++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    timepoints[i] = t;
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +      results[13 * i + j] = variables0[j];
 | 
											
												
													
														|  | 
 |  | +      // printf("%f ", results[13 * i + j]);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    // printf("\n");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (i < num_save - 1) {
 | 
											
												
													
														|  | 
 |  | +      propagate_trajectories_block(variables0, nu, chi, xi_rot, xi_alpha, dt, save_interval);
 | 
											
												
													
														|  | 
 |  | +      t += save_interval * dt;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_reduced_trajectories_block(double* variables, double nu, double tau, double dt, int num_steps) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double k1[5];
 | 
											
												
													
														|  | 
 |  | +  double k2[5];
 | 
											
												
													
														|  | 
 |  | +  double intermed[5];
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<num_steps; i++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    eq_system_reduced(variables, nu, tau, k1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<5; j++) {
 | 
											
												
													
														|  | 
 |  | +      intermed[j] = variables[j] + 2. / 3. * dt * k1[j];
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    eq_system_reduced(intermed, nu, tau, k2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<5; j++) {
 | 
											
												
													
														|  | 
 |  | +      variables[j] = variables[j] + dt * (1.0 / 4.0) * (k1[j] + 3 * k2[j]);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_reduced_trajectories(double* variables0, double nu, double tau,
 | 
											
												
													
														|  | 
 |  | +                            double t_span, double dt, int num_save,
 | 
											
												
													
														|  | 
 |  | +                            double* results, double* timepoints, int* nfev) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Should be len(results) / 5 = len(timepoints) = num_save
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +  int save_interval = round(t_span / (dt * (num_save - 1)));
 | 
											
												
													
														|  | 
 |  | +  dt = t_span / (save_interval * (num_save - 1));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  nfev[0] = 2 * save_interval * (num_save - 1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<num_save; i++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    timepoints[i] = t;
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<5; j++) {
 | 
											
												
													
														|  | 
 |  | +      results[5 * i + j] = variables0[j];
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (i < num_save - 1) {
 | 
											
												
													
														|  | 
 |  | +      propagate_reduced_trajectories_block(variables0, nu, tau, dt, save_interval);
 | 
											
												
													
														|  | 
 |  | +      t += save_interval * dt;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void eq_system_drag(double* variables, double* grad_theta, double* grad_phi,
 | 
											
												
													
														|  | 
 |  | +                    double nu, double chi, double mu, double xi_rot, double xi_alpha, double* dy_dt) {
 | 
											
												
													
														|  | 
 |  | +    // System of differential equations. y=[theta_k, phi_k, psi_k, alpha0] (len(y)=13)
 | 
											
												
													
														|  | 
 |  | +    // grad_theta contains the etheta component of velocity gradient in radial direction
 | 
											
												
													
														|  | 
 |  | +    // grad_phi contains the ephi component of velocity gradient in radial direction
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double thetas[4];
 | 
											
												
													
														|  | 
 |  | +    double phis[4];
 | 
											
												
													
														|  | 
 |  | +    double psis[4];
 | 
											
												
													
														|  | 
 |  | +    double delta_psi[4];
 | 
											
												
													
														|  | 
 |  | +    double alpha0 = variables[12];
 | 
											
												
													
														|  | 
 |  | +    double average_psi[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    psi_avg(&variables[0], &variables[4], alpha0, average_psi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +      thetas[i] = variables[i];
 | 
											
												
													
														|  | 
 |  | +      phis[i] = variables[4 + i];
 | 
											
												
													
														|  | 
 |  | +      psis[i] = variables[8 + i];
 | 
											
												
													
														|  | 
 |  | +      delta_psi[i] = psis[i] - average_psi[i];
 | 
											
												
													
														|  | 
 |  | +      delta_psi[i] -= M_PI * (2 * floor((delta_psi[i]+M_PI) / (2 * M_PI)));  // map into the interval [-pi , pi]
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double theta_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double phi_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double psi_deriv[4];
 | 
											
												
													
														|  | 
 |  | +    double alpha0_deriv = df_dalpha0(delta_psi, chi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    df_dtheta(thetas, phis, delta_psi, 0, theta_deriv);  // chi=0 for stability
 | 
											
												
													
														|  | 
 |  | +    df_dphi(thetas, phis, delta_psi, 0, phi_deriv);  // chi=0 for stability
 | 
											
												
													
														|  | 
 |  | +    df_dpsi(delta_psi, chi, psi_deriv);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double complex compl_velocity_conj[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +      // dtheta/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[k] = -theta_deriv[k] + nu * cos(psis[k]) - mu * grad_theta[k];
 | 
											
												
													
														|  | 
 |  | +      // dphi/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[4 + k] = -phi_deriv[k] / (sin(thetas[k]) * sin(thetas[k])) +
 | 
											
												
													
														|  | 
 |  | +                      (nu * sin(psis[k]) - mu * grad_phi[k]) / sin(thetas[k]);
 | 
											
												
													
														|  | 
 |  | +      // dpsi/dt
 | 
											
												
													
														|  | 
 |  | +      dy_dt[8 + k] = -1 / xi_rot * psi_deriv[k] - cos(thetas[k]) * dy_dt[4 + k];
 | 
											
												
													
														|  | 
 |  | +      // conjugated complex velocity
 | 
											
												
													
														|  | 
 |  | +      compl_velocity_conj[k] = dy_dt[k] - I * sin(thetas[k]) * dy_dt[4 + k];
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // dalpha0/dt
 | 
											
												
													
														|  | 
 |  | +    double inner_summand;
 | 
											
												
													
														|  | 
 |  | +    double outer_sum=0;
 | 
											
												
													
														|  | 
 |  | +    for (int k=0; k<4; k++) {
 | 
											
												
													
														|  | 
 |  | +      inner_summand = 0;
 | 
											
												
													
														|  | 
 |  | +      for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +        if (j != k) {
 | 
											
												
													
														|  | 
 |  | +          inner_summand += cimag( stereogr_proj(thetas[k], phis[k]) *
 | 
											
												
													
														|  | 
 |  | +                          compl_velocity_conj[k] /
 | 
											
												
													
														|  | 
 |  | +                          (stereogr_proj(thetas[k], phis[k]) - stereogr_proj(thetas[j], phis[j])) );
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      outer_sum += 1 / 8. * ( (1 + cos(thetas[k])) * dy_dt[4 + k] + 2 / sin(thetas[k]) * inner_summand );
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    dy_dt[12] = -1 / xi_alpha * alpha0_deriv + outer_sum;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_trajectories_step_drag(double* variables, double* grad_theta, double* grad_phi,
 | 
											
												
													
														|  | 
 |  | +                                      double nu, double chi, double mu, double xi_rot, double xi_alpha,
 | 
											
												
													
														|  | 
 |  | +                                      double dt) {
 | 
											
												
													
														|  | 
 |  | +  // One step of propagation with viscous drag
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double k1[13];
 | 
											
												
													
														|  | 
 |  | +  double k2[13];
 | 
											
												
													
														|  | 
 |  | +  double intermed[13];
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  eq_system_drag(variables, grad_theta, grad_phi, nu, chi, mu, xi_rot, xi_alpha, k1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +    intermed[j] = variables[j] + 2. / 3. * dt * k1[j];
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  eq_system_drag(intermed, grad_theta, grad_phi, nu, chi, mu, xi_rot, xi_alpha, k2);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +    variables[j] = variables[j] + dt * (1.0 / 4.0) * (k1[j] + 3 * k2[j]);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void gaussian_belt(double* variables, double* grad_theta, double* grad_phi, double* velocity) {
 | 
											
												
													
														|  | 
 |  | +  // test function for generating the gradient field as a belt around the equator
 | 
											
												
													
														|  | 
 |  | +  double sigma = 0.3;
 | 
											
												
													
														|  | 
 |  | +  double magnitude;
 | 
											
												
													
														|  | 
 |  | +  double in_exponent;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<4; i++) {
 | 
											
												
													
														|  | 
 |  | +    in_exponent = (variables[i] - M_PI / 2) / sigma;
 | 
											
												
													
														|  | 
 |  | +    magnitude = velocity[i] / (sigma * sqrt(2 * M_PI)) * exp(-0.5 * in_exponent * in_exponent);
 | 
											
												
													
														|  | 
 |  | +    grad_theta[i] = magnitude * cos(variables[8 + i]);
 | 
											
												
													
														|  | 
 |  | +    grad_phi[i] = magnitude * sin(variables[8 + i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void propagate_trajectories_drag(double* variables0, double nu, double chi, double mu,
 | 
											
												
													
														|  | 
 |  | +                                double xi_rot, double xi_alpha,
 | 
											
												
													
														|  | 
 |  | +                                double t_span, double dt, int num_save, double* results,
 | 
											
												
													
														|  | 
 |  | +                                double* timepoints, int* nfev) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Should be len(results) / 13 = len(timepoints) = num_save
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double t = 0;
 | 
											
												
													
														|  | 
 |  | +  int save_interval = round(t_span / (dt * (num_save - 1)));
 | 
											
												
													
														|  | 
 |  | +  dt = t_span / (save_interval * (num_save - 1));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double grad_theta[4];
 | 
											
												
													
														|  | 
 |  | +  double grad_phi[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  nfev[0] = 2 * save_interval * (num_save - 1);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<num_save; i++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    timepoints[i] = t;
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<13; j++) {
 | 
											
												
													
														|  | 
 |  | +      results[13 * i + j] = variables0[j];
 | 
											
												
													
														|  | 
 |  | +      // printf("%f ", results[13 * i + j]);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    // printf("\n");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double velocity[4];
 | 
											
												
													
														|  | 
 |  | +    for (int i=0; i<4; i++) {velocity[i] = nu;}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (i < num_save - 1) {
 | 
											
												
													
														|  | 
 |  | +      for (int k=0; k<save_interval; k++) {
 | 
											
												
													
														|  | 
 |  | +        gaussian_belt(variables0, grad_theta, grad_phi, velocity);
 | 
											
												
													
														|  | 
 |  | +        propagate_trajectories_step_drag(variables0, grad_theta, grad_phi, nu, chi, mu, xi_rot, xi_alpha, dt);
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      t += save_interval * dt;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double psi_around_defect(double theta, double phi, double psi,
 | 
											
												
													
														|  | 
 |  | +  double theta_defect, double phi_defect, double psi_defect, double radial_distance) {
 | 
											
												
													
														|  | 
 |  | +  /*
 | 
											
												
													
														|  | 
 |  | +  Translation of defect velocity direction to surrounding points. Does interpolation between
 | 
											
												
													
														|  | 
 |  | +  defect direction psi_theta and previously calculated direction psi
 | 
											
												
													
														|  | 
 |  | +  */
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double coord_defect[3];
 | 
											
												
													
														|  | 
 |  | +  double coord[3];
 | 
											
												
													
														|  | 
 |  | +  double axis[3];
 | 
											
												
													
														|  | 
 |  | +  double axis_normalization;
 | 
											
												
													
														|  | 
 |  | +  double cos_angle;
 | 
											
												
													
														|  | 
 |  | +  double angle;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  sph_to_cart(theta_defect, phi_defect, coord_defect);
 | 
											
												
													
														|  | 
 |  | +  sph_to_cart(theta, phi, coord);
 | 
											
												
													
														|  | 
 |  | +  cross_product(coord_defect, coord, axis);
 | 
											
												
													
														|  | 
 |  | +  axis_normalization = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
 | 
											
												
													
														|  | 
 |  | +  axis[0] = axis[0] / axis_normalization;
 | 
											
												
													
														|  | 
 |  | +  axis[1] = axis[1] / axis_normalization;
 | 
											
												
													
														|  | 
 |  | +  axis[2] = axis[2] / axis_normalization;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  cos_angle = cos_beta_ij(theta_defect, phi_defect, theta, phi);
 | 
											
												
													
														|  | 
 |  | +  angle = acos(cos_angle);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double defect_dir[3];
 | 
											
												
													
														|  | 
 |  | +  double vec_phi_defect[3];
 | 
											
												
													
														|  | 
 |  | +  double vec_theta_defect[3];
 | 
											
												
													
														|  | 
 |  | +  double cos_psi_defect = cos(psi_defect);
 | 
											
												
													
														|  | 
 |  | +  double sin_psi_defect = sin(psi_defect);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  ephi(phi_defect, vec_phi_defect);
 | 
											
												
													
														|  | 
 |  | +  etheta(phi_defect, theta_defect, vec_theta_defect);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  defect_dir[0] = cos_psi_defect * vec_theta_defect[0] + sin_psi_defect * vec_phi_defect[0];
 | 
											
												
													
														|  | 
 |  | +  defect_dir[1] = cos_psi_defect * vec_theta_defect[1] + sin_psi_defect * vec_phi_defect[1];
 | 
											
												
													
														|  | 
 |  | +  defect_dir[2] = cos_psi_defect * vec_theta_defect[2] + sin_psi_defect * vec_phi_defect[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // propagated (translated) defect direction
 | 
											
												
													
														|  | 
 |  | +  double propag_dir[3];
 | 
											
												
													
														|  | 
 |  | +  rodrigues_rotation(defect_dir, angle, axis, propag_dir);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // local coordiantes in he point of interest
 | 
											
												
													
														|  | 
 |  | +  double vec_phi[3];
 | 
											
												
													
														|  | 
 |  | +  double vec_theta[3];
 | 
											
												
													
														|  | 
 |  | +  double psi_propag;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  ephi(phi, vec_phi);
 | 
											
												
													
														|  | 
 |  | +  etheta(phi, theta, vec_theta);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // linear interpolation if radial distance is between 0.5 and 1 in units of rho
 | 
											
												
													
														|  | 
 |  | +  // could be done with rodrigues but we used new_v = (a*v0 + (1-a)*v1) * renormalization
 | 
											
												
													
														|  | 
 |  | +  double renormalization;  // for the interpolated vector to have the same length
 | 
											
												
													
														|  | 
 |  | +  double interp_factor;
 | 
											
												
													
														|  | 
 |  | +  double cos_psi = cos(psi);
 | 
											
												
													
														|  | 
 |  | +  double sin_psi = sin(psi);
 | 
											
												
													
														|  | 
 |  | +  double previous_dir[3]; // v0 (if as v1, we consider the propagated defect direction)
 | 
											
												
													
														|  | 
 |  | +  double v0_v1;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if (radial_distance > 0.5 && radial_distance < 1) {
 | 
											
												
													
														|  | 
 |  | +    interp_factor = 2 * (1 - radial_distance);
 | 
											
												
													
														|  | 
 |  | +    previous_dir[0] = cos_psi * vec_theta[0] + sin_psi * vec_phi[0];
 | 
											
												
													
														|  | 
 |  | +    previous_dir[1] = cos_psi * vec_theta[1] + sin_psi * vec_phi[1];
 | 
											
												
													
														|  | 
 |  | +    previous_dir[2] = cos_psi * vec_theta[2] + sin_psi * vec_phi[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    v0_v1 = previous_dir[0] * propag_dir[0] + previous_dir[1] * propag_dir[1] + previous_dir[2] * propag_dir[2];
 | 
											
												
													
														|  | 
 |  | +    renormalization = sqrt(1 / (interp_factor*interp_factor + (1 - interp_factor) * (1 - interp_factor) +
 | 
											
												
													
														|  | 
 |  | +                      2 * interp_factor * (1 - interp_factor) * v0_v1));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    propag_dir[0] = (interp_factor * propag_dir[0] + (1 - interp_factor) * previous_dir[0]) * renormalization;
 | 
											
												
													
														|  | 
 |  | +    propag_dir[1] = (interp_factor * propag_dir[1] + (1 - interp_factor) * previous_dir[1]) * renormalization;
 | 
											
												
													
														|  | 
 |  | +    propag_dir[2] = (interp_factor * propag_dir[2] + (1 - interp_factor) * previous_dir[2]) * renormalization;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // projection to local coordinate axes
 | 
											
												
													
														|  | 
 |  | +  double sin_psi_propag = propag_dir[0] * vec_phi[0] + propag_dir[1] * vec_phi[1] + propag_dir[2] * vec_phi[2];
 | 
											
												
													
														|  | 
 |  | +  double cos_psi_propag = propag_dir[0] * vec_theta[0] + propag_dir[1] * vec_theta[1] + propag_dir[2] * vec_theta[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  psi_propag = atan2(sin_psi_propag, cos_psi_propag);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return psi_propag;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void velocity_field(double* defect_config, int n, double* lattice_thetas, double* lattice_phis,
 | 
											
												
													
														|  | 
 |  | +  double nu, double rho, double* velocities) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // printf("Slow C function.\n");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double psi_bar[4];
 | 
											
												
													
														|  | 
 |  | +  psi_avg(&defect_config[0], &defect_config[4], defect_config[12], psi_bar);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double complex z_defect[4];
 | 
											
												
													
														|  | 
 |  | +  double delta_psi[4];
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i< 4; i++) {
 | 
											
												
													
														|  | 
 |  | +    z_defect[i] = stereogr_proj(defect_config[i], defect_config[4+i]);
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = defect_config[8 + i] - psi_bar[i];
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = delta_psi[i] - 2 * M_PI * floor((delta_psi[i] + M_PI) / (2 * M_PI));
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double alpha;
 | 
											
												
													
														|  | 
 |  | +  double dalpha_dphi, dalpha_dtheta;
 | 
											
												
													
														|  | 
 |  | +  double u_theta, u_phi;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double complex sum_in_alpha_eq;
 | 
											
												
													
														|  | 
 |  | +  double sum_in_alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +  double cos_beta_defect;
 | 
											
												
													
														|  | 
 |  | +  double beta_defect;
 | 
											
												
													
														|  | 
 |  | +  double dbeta_dphi, dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +  double alpha_eq, alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +  double dalpha_eq_dphi, dalpha_eq_dtheta;
 | 
											
												
													
														|  | 
 |  | +  double dalpha_tilde_dphi, dalpha_tilde_dtheta;
 | 
											
												
													
														|  | 
 |  | +  double complex sum_in_dalpha_eq;
 | 
											
												
													
														|  | 
 |  | +  int cutoff;
 | 
											
												
													
														|  | 
 |  | +  int direction_cutoff;
 | 
											
												
													
														|  | 
 |  | +  double new_psi;  // for propagating flow direction near the defects
 | 
											
												
													
														|  | 
 |  | +  double defect_dist;  // distance from the closest defect
 | 
											
												
													
														|  | 
 |  | +  double velocity_norm;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double ln1_rho = log(1/rho);
 | 
											
												
													
														|  | 
 |  | +  double vec_phi[3];
 | 
											
												
													
														|  | 
 |  | +  double vec_theta[3];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double complex z_point;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<n; i++) {
 | 
											
												
													
														|  | 
 |  | +    sum_in_alpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    sum_in_alpha_tilde = 0;
 | 
											
												
													
														|  | 
 |  | +    sum_in_dalpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    direction_cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    defect_dist = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    dalpha_tilde_dphi = 0;
 | 
											
												
													
														|  | 
 |  | +    dalpha_tilde_dtheta = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // numerical correction for the lattice point exactly at the north pole (needed for the stereographic projection).
 | 
											
												
													
														|  | 
 |  | +    if (lattice_thetas[i] < 1.0E-15) {
 | 
											
												
													
														|  | 
 |  | +      lattice_thetas[i] = 1.0E-15;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    z_point = stereogr_proj(lattice_thetas[i], lattice_phis[i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      cos_beta_defect = cos_beta_ij(lattice_thetas[i], lattice_phis[i], defect_config[j], defect_config[4 + j]);
 | 
											
												
													
														|  | 
 |  | +      beta_defect = acos(cos_beta_defect);
 | 
											
												
													
														|  | 
 |  | +      if (beta_defect < 1.25 * rho) {
 | 
											
												
													
														|  | 
 |  | +        cutoff = 1;  // possible velocity cutoff near the defects (fixed defect speed, diverges otherwise)
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      if (beta_defect < rho) {
 | 
											
												
													
														|  | 
 |  | +        defect_dist = beta_defect / rho;  // distance from the defect in units of rho
 | 
											
												
													
														|  | 
 |  | +        direction_cutoff = j + 1;  // possible direction cutoff near the defects
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      dbeta_dphi = -dcos_beta_dphi(lattice_thetas[i], lattice_phis[i], defect_config[j], defect_config[4 + j])
 | 
											
												
													
														|  | 
 |  | +                    / sqrt(1 - cos_beta_defect * cos_beta_defect);
 | 
											
												
													
														|  | 
 |  | +      dbeta_dtheta = -dcos_beta_dtheta(lattice_thetas[i], lattice_phis[i], defect_config[j], defect_config[4 + j])
 | 
											
												
													
														|  | 
 |  | +                      / sqrt(1 - cos_beta_defect * cos_beta_defect);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_eq += clog(z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_tilde += delta_psi[j] * (log(1 / sin(beta_defect / 2)) - 1);
 | 
											
												
													
														|  | 
 |  | +      sum_in_dalpha_eq += z_point / (z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dphi += -delta_psi[j] / (4 * ln1_rho * tan(beta_defect / 2)) * dbeta_dphi;
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dtheta += -delta_psi[j] / (4 * ln1_rho * tan(beta_defect / 2)) * dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    alpha_eq = lattice_phis[i] - defect_config[12] - 0.5 * cimag(sum_in_alpha_eq);
 | 
											
												
													
														|  | 
 |  | +    alpha_tilde = 1 / (2 * ln1_rho) * sum_in_alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +    alpha = alpha_eq + alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    dalpha_eq_dphi = 1 - 0.5 * creal(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +    dalpha_eq_dtheta = 1 / (2 * sin(lattice_thetas[i])) * cimag(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    dalpha_dphi = dalpha_eq_dphi + dalpha_tilde_dphi;
 | 
											
												
													
														|  | 
 |  | +    dalpha_dtheta = dalpha_eq_dtheta + dalpha_tilde_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // averaged delta psi for higher accuracy of renormalization
 | 
											
												
													
														|  | 
 |  | +    double avg_delta_psi = 0.25 * (fabs(delta_psi[0]) + fabs(delta_psi[1]) + fabs(delta_psi[2]) + fabs(delta_psi[3]));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double normalization = 2 * rho * nu / sqrt(1 + (avg_delta_psi/ln1_rho) * (avg_delta_psi/ln1_rho));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    u_theta = normalization * (sin(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - cos(2 * alpha) / sin(lattice_thetas[i]) * (cos(lattice_thetas[i]) + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +    u_phi = normalization * (-cos(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - sin(2 * alpha) / sin(lattice_thetas[i]) * (cos(lattice_thetas[i]) + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    velocity_norm = sqrt(u_theta * u_theta + u_phi * u_phi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // velocity cutoff near defects
 | 
											
												
													
														|  | 
 |  | +    if (cutoff == 1 && velocity_norm > nu) {
 | 
											
												
													
														|  | 
 |  | +      u_theta = u_theta * nu / velocity_norm;  // Renormalizing velocity near defects to exactly the defect speed
 | 
											
												
													
														|  | 
 |  | +      u_phi = u_phi * nu / velocity_norm;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // fixing the velocity field direction close to the defects
 | 
											
												
													
														|  | 
 |  | +    double psi_lattice;
 | 
											
												
													
														|  | 
 |  | +    if (direction_cutoff != 0) {
 | 
											
												
													
														|  | 
 |  | +      psi_lattice = atan2(u_phi, u_theta);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      new_psi = psi_around_defect(lattice_thetas[i], lattice_phis[i], psi_lattice, defect_config[direction_cutoff - 1],
 | 
											
												
													
														|  | 
 |  | +        defect_config[4 + direction_cutoff - 1], defect_config[8 + direction_cutoff - 1], defect_dist);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      u_theta = cos(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +      u_phi = sin(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    ephi(lattice_phis[i], vec_phi);
 | 
											
												
													
														|  | 
 |  | +    etheta(lattice_phis[i], lattice_thetas[i], vec_theta);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i] = u_theta * vec_theta[0] + u_phi * vec_phi[0];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+1] = u_theta * vec_theta[1] + u_phi * vec_phi[1];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+2] = u_theta * vec_theta[2] + u_phi * vec_phi[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +double dot_product(double* vec1,double* vec2) {
 | 
											
												
													
														|  | 
 |  | +  return vec1[0] * vec2[0] + vec1[1] * vec2[1] +vec1[2] * vec2[2];
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void velocity_field_fast(double* defect_config, int n, double* lattice_thetas, double* lattice_phis,
 | 
											
												
													
														|  | 
 |  | +  double* lattice_basis, double nu, double rho, double* velocities, const int num_cores) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // printf("Fast C function.\n");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double psi_bar[4];
 | 
											
												
													
														|  | 
 |  | +  psi_avg(&defect_config[0], &defect_config[4], defect_config[12], psi_bar);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double complex z_defect[4];
 | 
											
												
													
														|  | 
 |  | +  double delta_psi[4];
 | 
											
												
													
														|  | 
 |  | +  double defect_cart[12];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i< 4; i++) {
 | 
											
												
													
														|  | 
 |  | +    z_defect[i] = stereogr_proj(defect_config[i], defect_config[4+i]);
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = defect_config[8 + i] - psi_bar[i];
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = delta_psi[i] - 2 * M_PI * floor((delta_psi[i] + M_PI) / (2 * M_PI));
 | 
											
												
													
														|  | 
 |  | +    sph_to_cart(defect_config[i], defect_config[4+i], &defect_cart[3*i]);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double ln1_rho = log(1/rho);
 | 
											
												
													
														|  | 
 |  | +  double vel_cutoff = cos(1.25 * rho);
 | 
											
												
													
														|  | 
 |  | +  double dir_cutoff = cos(rho);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // double start = omp_get_wtime();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  #pragma omp parallel for num_threads(num_cores) schedule(dynamic, 2500)
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<n; i++) {
 | 
											
												
													
														|  | 
 |  | +    double complex sum_in_alpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    double complex sum_in_dalpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    double sum_in_alpha_tilde = 0;
 | 
											
												
													
														|  | 
 |  | +    int cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    int direction_cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    double defect_dist = 0;  // distance from the closest defect
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_tilde_dphi = 0;
 | 
											
												
													
														|  | 
 |  | +    double dalpha_tilde_dtheta = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double sin_lat_th = sin(lattice_thetas[i]);
 | 
											
												
													
														|  | 
 |  | +    double cos_lat_th = cos(lattice_thetas[i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double cos_beta_defect;
 | 
											
												
													
														|  | 
 |  | +    double sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +    double tan_beta_half;
 | 
											
												
													
														|  | 
 |  | +    double sin_beta_half;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dbeta_dphi, dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // numerical correction for the lattice point exactly at the north pole (needed for the stereographic projection).
 | 
											
												
													
														|  | 
 |  | +    if (lattice_thetas[i] < 1.0E-15) {
 | 
											
												
													
														|  | 
 |  | +      lattice_thetas[i] = 1.0E-15;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double complex z_point = stereogr_proj(lattice_thetas[i], lattice_phis[i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      cos_beta_defect = dot_product(&lattice_basis[9*i], &defect_cart[3*j]);
 | 
											
												
													
														|  | 
 |  | +      if (cos_beta_defect > vel_cutoff) {
 | 
											
												
													
														|  | 
 |  | +        cutoff = 1;  // possible velocity cutoff near the defects (fixed defect speed, diverges otherwise)
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      if (cos_beta_defect > dir_cutoff) {
 | 
											
												
													
														|  | 
 |  | +        defect_dist = acos(cos_beta_defect) / rho;  // distance from the defect in units of rho
 | 
											
												
													
														|  | 
 |  | +        direction_cutoff = j + 1;  // possible direction cutoff near the defects
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sin_beta_defect = sqrt(1 - cos_beta_defect * cos_beta_defect);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      // derivatives over theta and phi are equal to scalar products with other basis vectors
 | 
											
												
													
														|  | 
 |  | +      dbeta_dtheta = -dot_product(&lattice_basis[9*i + 3], &defect_cart[3*j]) / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +      dbeta_dphi = -dot_product(&lattice_basis[9*i + 6], &defect_cart[3*j]) * sin_lat_th / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sin_beta_half = sqrt((1 - cos_beta_defect) / 2);
 | 
											
												
													
														|  | 
 |  | +      tan_beta_half = (1 - cos_beta_defect) / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_eq += clog(z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_tilde += delta_psi[j] * (log(1 / sin_beta_half) - 1);
 | 
											
												
													
														|  | 
 |  | +      sum_in_dalpha_eq += z_point / (z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dphi += -delta_psi[j] / (4 * ln1_rho * tan_beta_half) * dbeta_dphi;
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dtheta += -delta_psi[j] / (4 * ln1_rho * tan_beta_half) * dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double alpha_eq = lattice_phis[i] - defect_config[12] - 0.5 * cimag(sum_in_alpha_eq);
 | 
											
												
													
														|  | 
 |  | +    double alpha_tilde = 1 / (2 * ln1_rho) * sum_in_alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +    double alpha = alpha_eq + alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_eq_dphi = 1 - 0.5 * creal(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +    double dalpha_eq_dtheta = 1 / (2 * sin_lat_th) * cimag(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_dphi = dalpha_eq_dphi + dalpha_tilde_dphi;
 | 
											
												
													
														|  | 
 |  | +    double dalpha_dtheta = dalpha_eq_dtheta + dalpha_tilde_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // averaged delta psi for higher accuracy of renormalization
 | 
											
												
													
														|  | 
 |  | +    double avg_delta_psi = 0.25 * (fabs(delta_psi[0]) + fabs(delta_psi[1]) + fabs(delta_psi[2]) + fabs(delta_psi[3]));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double normalization = 2 * rho * nu / sqrt(1 + (avg_delta_psi/ln1_rho) * (avg_delta_psi/ln1_rho));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double u_theta = normalization * (sin(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - cos(2 * alpha) / sin_lat_th * (cos_lat_th + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +    double u_phi = normalization * (-cos(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - sin(2 * alpha) / sin_lat_th * (cos_lat_th + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double velocity_norm = sqrt(u_theta * u_theta + u_phi * u_phi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // velocity cutoff near defects
 | 
											
												
													
														|  | 
 |  | +    if (cutoff == 1 && velocity_norm > nu) {
 | 
											
												
													
														|  | 
 |  | +      u_theta = u_theta * nu / velocity_norm;  // Renormalizing velocity near defects to exactly the defect speed
 | 
											
												
													
														|  | 
 |  | +      u_phi = u_phi * nu / velocity_norm;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // fixing the velocity field direction close to the defects
 | 
											
												
													
														|  | 
 |  | +    double psi_lattice;
 | 
											
												
													
														|  | 
 |  | +    double new_psi;  // for propagating flow direction near the defects
 | 
											
												
													
														|  | 
 |  | +    if (direction_cutoff != 0) {
 | 
											
												
													
														|  | 
 |  | +      psi_lattice = atan2(u_phi, u_theta);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      new_psi = psi_around_defect(lattice_thetas[i], lattice_phis[i], psi_lattice, defect_config[direction_cutoff - 1],
 | 
											
												
													
														|  | 
 |  | +        defect_config[4 + direction_cutoff - 1], defect_config[8 + direction_cutoff - 1], defect_dist);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      u_theta = cos(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +      u_phi = sin(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i] = u_theta * lattice_basis[9*i + 3] + u_phi * lattice_basis[9*i + 6];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+1] = u_theta * lattice_basis[9*i + 4] + u_phi * lattice_basis[9*i + 7];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+2] = u_theta * lattice_basis[9*i + 5] + u_phi * lattice_basis[9*i + 8];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // double end = omp_get_wtime();
 | 
											
												
													
														|  | 
 |  | +  // printf("Loop time: %f\n",end - start);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void velocity_field_drag(double* defect_config, int n, double* lattice_thetas, double* lattice_phis,
 | 
											
												
													
														|  | 
 |  | +  double* lattice_basis, double* lattice_grad_theta, double* lattice_grad_phi,
 | 
											
												
													
														|  | 
 |  | +  double nu, double mu, double rho, double* velocities, const int num_cores) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // printf("Fast C function.\n");
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double psi_bar[4];
 | 
											
												
													
														|  | 
 |  | +  psi_avg(&defect_config[0], &defect_config[4], defect_config[12], psi_bar);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double complex z_defect[4];
 | 
											
												
													
														|  | 
 |  | +  double delta_psi[4];
 | 
											
												
													
														|  | 
 |  | +  double defect_cart[12];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i< 4; i++) {
 | 
											
												
													
														|  | 
 |  | +    z_defect[i] = stereogr_proj(defect_config[i], defect_config[4+i]);
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = defect_config[8 + i] - psi_bar[i];
 | 
											
												
													
														|  | 
 |  | +    delta_psi[i] = delta_psi[i] - 2 * M_PI * floor((delta_psi[i] + M_PI) / (2 * M_PI));
 | 
											
												
													
														|  | 
 |  | +    sph_to_cart(defect_config[i], defect_config[4+i], &defect_cart[3*i]);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  double ln1_rho = log(1/rho);
 | 
											
												
													
														|  | 
 |  | +  double vel_cutoff = cos(1.25 * rho);
 | 
											
												
													
														|  | 
 |  | +  double dir_cutoff = cos(rho);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // double start = omp_get_wtime();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  #pragma omp parallel for num_threads(num_cores) schedule(dynamic, 2500)
 | 
											
												
													
														|  | 
 |  | +  for (int i=0; i<n; i++) {
 | 
											
												
													
														|  | 
 |  | +    double complex sum_in_alpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    double complex sum_in_dalpha_eq = 0;
 | 
											
												
													
														|  | 
 |  | +    double sum_in_alpha_tilde = 0;
 | 
											
												
													
														|  | 
 |  | +    int cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    int direction_cutoff = 0;
 | 
											
												
													
														|  | 
 |  | +    double defect_dist = 0;  // distance from the closest defect
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_tilde_dphi = 0;
 | 
											
												
													
														|  | 
 |  | +    double dalpha_tilde_dtheta = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double sin_lat_th = sin(lattice_thetas[i]);
 | 
											
												
													
														|  | 
 |  | +    double cos_lat_th = cos(lattice_thetas[i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double cos_beta_defect;
 | 
											
												
													
														|  | 
 |  | +    double sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +    double tan_beta_half;
 | 
											
												
													
														|  | 
 |  | +    double sin_beta_half;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dbeta_dphi, dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // numerical correction for the lattice point exactly at the north pole (needed for the stereographic projection).
 | 
											
												
													
														|  | 
 |  | +    if (lattice_thetas[i] < 1.0E-15) {
 | 
											
												
													
														|  | 
 |  | +      lattice_thetas[i] = 1.0E-15;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double complex z_point = stereogr_proj(lattice_thetas[i], lattice_phis[i]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    for (int j=0; j<4; j++) {
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      cos_beta_defect = dot_product(&lattice_basis[9*i], &defect_cart[3*j]);
 | 
											
												
													
														|  | 
 |  | +      if (cos_beta_defect > vel_cutoff) {
 | 
											
												
													
														|  | 
 |  | +        cutoff = 1;  // possible velocity cutoff near the defects (fixed defect speed, diverges otherwise)
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      if (cos_beta_defect > dir_cutoff) {
 | 
											
												
													
														|  | 
 |  | +        defect_dist = acos(cos_beta_defect) / rho;  // distance from the defect in units of rho
 | 
											
												
													
														|  | 
 |  | +        direction_cutoff = j + 1;  // possible direction cutoff near the defects
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sin_beta_defect = sqrt(1 - cos_beta_defect * cos_beta_defect);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      // derivatives over theta and phi are equal to scalar products with other basis vectors
 | 
											
												
													
														|  | 
 |  | +      dbeta_dtheta = -dot_product(&lattice_basis[9*i + 3], &defect_cart[3*j]) / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +      dbeta_dphi = -dot_product(&lattice_basis[9*i + 6], &defect_cart[3*j]) * sin_lat_th / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sin_beta_half = sqrt((1 - cos_beta_defect) / 2);
 | 
											
												
													
														|  | 
 |  | +      tan_beta_half = (1 - cos_beta_defect) / sin_beta_defect;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_eq += clog(z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +      sum_in_alpha_tilde += delta_psi[j] * (log(1 / sin_beta_half) - 1);
 | 
											
												
													
														|  | 
 |  | +      sum_in_dalpha_eq += z_point / (z_point - z_defect[j]);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dphi += -delta_psi[j] / (4 * ln1_rho * tan_beta_half) * dbeta_dphi;
 | 
											
												
													
														|  | 
 |  | +      dalpha_tilde_dtheta += -delta_psi[j] / (4 * ln1_rho * tan_beta_half) * dbeta_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double alpha_eq = lattice_phis[i] - defect_config[12] - 0.5 * cimag(sum_in_alpha_eq);
 | 
											
												
													
														|  | 
 |  | +    double alpha_tilde = 1 / (2 * ln1_rho) * sum_in_alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +    double alpha = alpha_eq + alpha_tilde;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_eq_dphi = 1 - 0.5 * creal(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +    double dalpha_eq_dtheta = 1 / (2 * sin_lat_th) * cimag(sum_in_dalpha_eq);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double dalpha_dphi = dalpha_eq_dphi + dalpha_tilde_dphi;
 | 
											
												
													
														|  | 
 |  | +    double dalpha_dtheta = dalpha_eq_dtheta + dalpha_tilde_dtheta;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // averaged delta psi for higher accuracy of renormalization
 | 
											
												
													
														|  | 
 |  | +    double avg_delta_psi = 0.25 * (fabs(delta_psi[0]) + fabs(delta_psi[1]) + fabs(delta_psi[2]) + fabs(delta_psi[3]));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double normalization = 2 * rho * nu / sqrt(1 + (avg_delta_psi/ln1_rho) * (avg_delta_psi/ln1_rho));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double u_theta = normalization * (sin(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - cos(2 * alpha) / sin_lat_th * (cos_lat_th + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +    double u_phi = normalization * (-cos(2 * alpha) * dalpha_dtheta
 | 
											
												
													
														|  | 
 |  | +                      - sin(2 * alpha) / sin_lat_th * (cos_lat_th + dalpha_dphi));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    double velocity_norm = sqrt(u_theta * u_theta + u_phi * u_phi);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // velocity cutoff near defects
 | 
											
												
													
														|  | 
 |  | +    if (cutoff == 1 && velocity_norm > nu) {
 | 
											
												
													
														|  | 
 |  | +      u_theta = u_theta * nu / velocity_norm;  // Renormalizing velocity near defects to exactly the defect speed
 | 
											
												
													
														|  | 
 |  | +      u_phi = u_phi * nu / velocity_norm;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    // fixing the velocity field direction close to the defects
 | 
											
												
													
														|  | 
 |  | +    double psi_lattice;
 | 
											
												
													
														|  | 
 |  | +    double new_psi;  // for propagating flow direction near the defects
 | 
											
												
													
														|  | 
 |  | +    if (direction_cutoff != 0) {
 | 
											
												
													
														|  | 
 |  | +      psi_lattice = atan2(u_phi, u_theta);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      new_psi = psi_around_defect(lattice_thetas[i], lattice_phis[i], psi_lattice, defect_config[direction_cutoff - 1],
 | 
											
												
													
														|  | 
 |  | +        defect_config[4 + direction_cutoff - 1], defect_config[8 + direction_cutoff - 1], defect_dist);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +      u_theta = cos(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +      u_phi = sin(new_psi) * nu;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    u_theta = u_theta - mu * lattice_grad_theta[i];
 | 
											
												
													
														|  | 
 |  | +    u_phi = u_phi - mu * lattice_grad_phi[i];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i] = u_theta * lattice_basis[9*i + 3] + u_phi * lattice_basis[9*i + 6];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+1] = u_theta * lattice_basis[9*i + 4] + u_phi * lattice_basis[9*i + 7];
 | 
											
												
													
														|  | 
 |  | +    velocities[3*i+2] = u_theta * lattice_basis[9*i + 5] + u_phi * lattice_basis[9*i + 8];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // double end = omp_get_wtime();
 | 
											
												
													
														|  | 
 |  | +  // printf("Loop time: %f\n",end - start);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 |