Ejemplo n.º 1
0
static int get_rotation_axis(SPGCONST int proper_rot[3][3])
{
  int i, axis = -1;
  int vec[3];

  /* No specific axis for I and -I */
  if (mat_check_identity_matrix_i3(proper_rot, identity)) {
    goto end;
  }

  /* Look for eigenvector = rotation axis */
  for (i = 0; i < NUM_ROT_AXES; i++) {
    mat_multiply_matrix_vector_i3(vec, proper_rot, rot_axes[i]);
    if (vec[0] == rot_axes[i][0] &&
	vec[1] == rot_axes[i][1] &&
	vec[2] == rot_axes[i][2]) {
      axis = i;
      break;
    }
  }
  
 end:
#ifdef SPGDEBUG
  if (axis == -1) {
    printf("rotation axis cound not found.\n");
  }
#endif
  
  return axis;
}
Ejemplo n.º 2
0
static int get_orthogonal_axis(int ortho_axes[],
			       SPGCONST int proper_rot[3][3],
			       const int rot_order)
{
  int i, num_ortho_axis;
  int vec[3];
  int sum_rot[3][3], rot[3][3];

  num_ortho_axis = 0;

  mat_copy_matrix_i3(sum_rot, identity);
  mat_copy_matrix_i3(rot, identity);
  for (i = 0; i < rot_order - 1; i++) {
    mat_multiply_matrix_i3(rot, proper_rot, rot);
    mat_add_matrix_i3(sum_rot, rot, sum_rot);
  }
  
  for (i = 0; i < NUM_ROT_AXES; i++) {
    mat_multiply_matrix_vector_i3(vec, sum_rot, rot_axes[i]);
    if (vec[0] == 0 &&
	vec[1] == 0 &&
	vec[2] == 0) {
      ortho_axes[num_ortho_axis] = i;
      num_ortho_axis++;
    }
  }

  return num_ortho_axis;
}
Ejemplo n.º 3
0
static int laue4m(int axes[3],
		  SPGCONST PointSymmetry * pointsym)
{
  int i, num_ortho_axis, norm, min_norm, is_found, tmpval;
  int axis_vec[3];
  int prop_rot[3][3], t_mat[3][3];
  int ortho_axes[NUM_ROT_AXES];

  for (i = 0; i < pointsym->size; i++) {
    get_proper_rotation(prop_rot, pointsym->rot[i]);

    /* Search foud-fold rotation */
    if ( mat_get_trace_i3(prop_rot) == 1) {
      /* The first axis */
      axes[2] = get_rotation_axis(prop_rot);
      break;
    }
  }

  /* The second axis */
  num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, 4);
  if (! num_ortho_axis) { goto err; }
  
  min_norm = 8;
  is_found = 0;
  for (i = 0; i < num_ortho_axis; i++) {
    norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]);
    if (norm < min_norm) {
      min_norm = norm;
      axes[0] = ortho_axes[i];
      is_found = 1;
    }
  }
  if (! is_found) { goto err; }
  
  /* The third axis */
  mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
  is_found = 0;
  for (i = 0; i < NUM_ROT_AXES; i++) {
    if (is_exist_axis(axis_vec, i)) {
      is_found = 1;
      axes[1] = i;
      break;
    }
  }
  if (! is_found) { goto err; }

  set_transformation_matrix(t_mat, axes);
  if (mat_get_determinant_i3(t_mat) < 0) {
    tmpval = axes[0];
    axes[0] = axes[1];
    axes[1] = tmpval;
  }

  return 1;

 err:
  return 0;
}
Ejemplo n.º 4
0
static int get_ir_reciprocal_mesh_distortion(int grid_address[][3],
                                             int ir_mapping_table[],
                                             const int mesh[3],
                                             const int is_shift[3],
                                             const MatINT *rot_reciprocal)
{
  int i, j, k, grid_point_rot, indivisible;
  int address_double[3], address_double_rot[3], divisor[3];

  kgd_get_all_grid_addresses(grid_address, mesh);

  for (i = 0; i < 3; i++) {
    divisor[i] = mesh[(i + 1) % 3] * mesh[(i + 2) % 3];
  }

#pragma omp parallel for private(j, k, grid_point_rot, address_double, address_double_rot)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    kgd_get_grid_address_double_mesh(address_double,
				     grid_address[i],
				     mesh,
				     is_shift);
    for (j = 0; j < 3; j++) {
      address_double[j] *= divisor[j];
    }
    ir_mapping_table[i] = i;
    for (j = 0; j < rot_reciprocal->size; j++) {
      mat_multiply_matrix_vector_i3(address_double_rot,
				    rot_reciprocal->mat[j],
				    address_double);
      for (k = 0; k < 3; k++) {
        indivisible = address_double_rot[k] % divisor[k];
        if (indivisible) {break;}
        address_double_rot[k] /= divisor[k];
        if ((address_double_rot[k] % 2 != 0 && is_shift[k] == 0) ||
            (address_double_rot[k] % 2 == 0 && is_shift[k] == 1)) {
          indivisible = 1;
          break;
        }
      }
      if (indivisible) {continue;}
      grid_point_rot = kgd_get_grid_point_double_mesh(address_double_rot, mesh);
      if (grid_point_rot < ir_mapping_table[i]) {
#ifdef _OPENMP
	ir_mapping_table[i] = grid_point_rot;
#else
	ir_mapping_table[i] = ir_mapping_table[grid_point_rot];
	break;
#endif
      }
    }
  }

  return get_num_ir(ir_mapping_table, mesh);
}
Ejemplo n.º 5
0
void kpt_get_grid_points_by_rotations(int rot_grid_points[],
				      const int address_orig[3],
				      const MatINT * rot_reciprocal,
				      const int mesh[3],
				      const int is_shift[3])
{
  int i;
  int address_double_orig[3], address_double[3];

  for (i = 0; i < 3; i++) {
    address_double_orig[i] = address_orig[i] * 2 + is_shift[i];
  }
  for (i = 0; i < rot_reciprocal->size; i++) {
    mat_multiply_matrix_vector_i3(address_double,
				  rot_reciprocal->mat[i],
				  address_double_orig);
    rot_grid_points[i] = get_grid_point_double_mesh(address_double, mesh);
  }
}
Ejemplo n.º 6
0
static int get_ir_reciprocal_mesh_normal(int grid_address[][3],
                                         int ir_mapping_table[],
                                         const int mesh[3],
                                         const int is_shift[3],
                                         const MatINT *rot_reciprocal)
{
  /* In the following loop, mesh is doubled. */
  /* Even and odd mesh numbers correspond to */
  /* is_shift[i] are 0 or 1, respectively. */
  /* is_shift = [0,0,0] gives Gamma center mesh. */
  /* grid: reducible grid points */
  /* ir_mapping_table: the mapping from each point to ir-point. */

  int i, j, grid_point_rot;
  int address_double[3], address_double_rot[3];

  kgd_get_all_grid_addresses(grid_address, mesh);

#pragma omp parallel for private(j, grid_point_rot, address_double, address_double_rot)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    kgd_get_grid_address_double_mesh(address_double,
				     grid_address[i],
				     mesh,
				     is_shift);
    ir_mapping_table[i] = i;
    for (j = 0; j < rot_reciprocal->size; j++) {
      mat_multiply_matrix_vector_i3(address_double_rot,
				    rot_reciprocal->mat[j],
				    address_double);
      grid_point_rot = kgd_get_grid_point_double_mesh(address_double_rot, mesh);
      if (grid_point_rot < ir_mapping_table[i]) {
#ifdef _OPENMP
	ir_mapping_table[i] = grid_point_rot;
#else
	ir_mapping_table[i] = ir_mapping_table[grid_point_rot];
	break;
#endif
      }
    }
  }

  return get_num_ir(ir_mapping_table, mesh);
}
Ejemplo n.º 7
0
void kpt_get_BZ_grid_points_by_rotations(int rot_grid_points[],
					 const int address_orig[3],
					 const MatINT * rot_reciprocal,
					 const int mesh[3],
					 const int is_shift[3],
					 const int bz_map[])
{
  int i;
  int address_double_orig[3], address_double[3], mesh_double[3], bzmesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
    bzmesh_double[i] = mesh[i] * 4;
    address_double_orig[i] = address_orig[i] * 2 + is_shift[i];
  }
  for (i = 0; i < rot_reciprocal->size; i++) {
    mat_multiply_matrix_vector_i3(address_double,
				  rot_reciprocal->mat[i],
				  address_double_orig);
    get_vector_modulo(address_double, bzmesh_double);
    rot_grid_points[i] =
      bz_map[get_grid_point_double_mesh(address_double, mesh_double)];
  }
}
Ejemplo n.º 8
0
static int laue3m(int axes[3],
		  SPGCONST PointSymmetry * pointsym)
{
  int i, is_found, tmpval, axis;
  int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3];
  int axis_vec[3];

  for (i = 0; i < pointsym->size; i++) {
    get_proper_rotation(prop_rot, pointsym->rot[i]);

    /* Search three-fold rotation */
    if (mat_get_trace_i3(prop_rot) == 0) {
      /* The first axis */
      axes[2] = get_rotation_axis(prop_rot);
      debug_print("laue3m prop_rot\n");
      debug_print_matrix_i3(prop_rot);
      break;
    }
  }

  is_found = 0;
  for (i = 0; i < pointsym->size; i++) {
    get_proper_rotation(prop_rot2, pointsym->rot[i]);

    /* Search two-fold rotation */
    if (! (mat_get_trace_i3(prop_rot2) == -1)) {
      continue;
    }

    /* The second axis */
    axis = get_rotation_axis(prop_rot2);
    if (! (axis == axes[2])) {
      axes[0] = axis;
      is_found = 1;
      break;
    }
  }
  if (! is_found) { goto err; }

  /* The third axis */
  mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
  is_found = 0;
  for (i = 0; i < NUM_ROT_AXES; i++) {
    is_found = is_exist_axis(axis_vec, i);
    if (is_found == 1) {
      axes[1] = i;
      break;
    }
    if (is_found == -1) {
      axes[1] = i + NUM_ROT_AXES;
      break;
    }
  }
  if (! is_found) { goto err; }

  set_transformation_matrix(t_mat, axes);
  if (mat_get_determinant_i3(t_mat) < 0) {
    tmpval = axes[0];
    axes[0] = axes[1];
    axes[1] = tmpval;
  }

  return 1;

 err:
  return 0;
}
Ejemplo n.º 9
0
static int laue_one_axis(int axes[3],
			 SPGCONST PointSymmetry * pointsym,
			 const int rot_order)
{
  int i, j, num_ortho_axis, det, is_found, tmpval;
  int axis_vec[3], tmp_axes[3];
  int prop_rot[3][3], t_mat[3][3];
  int ortho_axes[NUM_ROT_AXES];

  debug_print("laue_one_axis with rot_order %d\n", rot_order);
  
  for (i = 0; i < pointsym->size; i++) {
    get_proper_rotation(prop_rot, pointsym->rot[i]);

    /* Search foud-fold rotation */
    if (rot_order == 4) {
      if (mat_get_trace_i3(prop_rot) == 1) {
	/* The first axis */
	axes[2] = get_rotation_axis(prop_rot);
	break;
      }
    }

    /* Search three-fold rotation */
    if (rot_order == 3) {
      if (mat_get_trace_i3(prop_rot) == 0) {
	/* The first axis */
	axes[2] = get_rotation_axis(prop_rot);
	break;
      }
    }
  }

  /* Candidates of the second axis */
  num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, rot_order);
  if (! num_ortho_axis) { goto err; }

  tmp_axes[1] = -1;
  tmp_axes[2] = axes[2];
  for (i = 0; i < num_ortho_axis; i++) {
    is_found = 0;
    tmp_axes[0] = ortho_axes[i];
    mat_multiply_matrix_vector_i3(axis_vec,
				  prop_rot,
				  rot_axes[tmp_axes[0]]);
    for (j = 0; j < num_ortho_axis; j++) {
      is_found = is_exist_axis(axis_vec, ortho_axes[j]);
      if (is_found == 1) {
	tmp_axes[1] = ortho_axes[j];
	break;
      }
      if (is_found == -1) {
	tmp_axes[1] = ortho_axes[j] + NUM_ROT_AXES;
	break;
      }
    }

    if (!is_found) { continue; }
    
    set_transformation_matrix(t_mat, tmp_axes);
    det = abs(mat_get_determinant_i3(t_mat));
    if (det < 4) { /* to avoid F-center choice det=4 */
      axes[0] = tmp_axes[0];
      axes[1] = tmp_axes[1];
      goto end;
    }
  }

 err: /* axes are not correctly found. */
  warning_print("spglib: Secondary axis is not found.");
  warning_print("(line %d, %s).\n", __LINE__, __FILE__);
  return 0;

 end:
  set_transformation_matrix(t_mat, axes);
  if (mat_get_determinant_i3(t_mat) < 0) {
    tmpval = axes[0];
    axes[0] = axes[1];
    axes[1] = tmpval;
  }

  debug_print("axes[0] = %d\n", axes[0]);
  debug_print("axes[1] = %d\n", axes[1]);
  debug_print("axes[2] = %d\n", axes[2]);

  return 1;

}
Ejemplo n.º 10
0
static int laue_one_axis( int axes[3],
			  const Symmetry * symmetry,
			  const int rot_order )
{
  int i, j, num_ortho_axis, det, min_det, is_found, tmpval;
  int axis_vec[3], tmp_axes[3];
  int prop_rot[3][3], t_mat[3][3];
  int ortho_axes[NUM_ROT_AXES];

  for ( i = 0; i < symmetry->size; i++ ) {
    get_proper_rotation( prop_rot, symmetry->rot[i] );

    /* Search foud-fold rotation */
    if ( rot_order == 4 ) {
      if (  mat_get_trace_i3( prop_rot ) == 1 ) {
	/* The first axis */
	axes[2] = get_rotation_axis( prop_rot );
	break;
      }
    }

    /* Search three-fold rotation */
    if ( rot_order == 3 ) {
      if (  mat_get_trace_i3( prop_rot ) == 0 ) {
	/* The first axis */
	axes[2] = get_rotation_axis( prop_rot );
	break;
      }
    }
  }

  /* Candidates of the second axis */
  num_ortho_axis = get_orthogonal_axis( ortho_axes, prop_rot, rot_order );
  if ( ! num_ortho_axis ) { goto err; }

  tmp_axes[2] = axes[2];
  min_det = 4;
  is_found = 0;
  for ( i = 0; i < num_ortho_axis; i++ ) {
    tmp_axes[0] = ortho_axes[i];
    mat_multiply_matrix_vector_i3( axis_vec, prop_rot,
				   rot_axes[tmp_axes[0]] );
    for ( j = 0; j < num_ortho_axis; j++ ) {
      is_found = is_exist_axis( axis_vec, ortho_axes[j] );
      if ( is_found == 1 ) {
	tmp_axes[1] = ortho_axes[j];
	break;
      }
      if ( is_found == -1 ) {
	tmp_axes[1] = ortho_axes[j] + NUM_ROT_AXES;
	break;
      }
    }

    get_transform_matrix( t_mat, tmp_axes );
    det = mat_get_determinant_i3( t_mat );
    if ( det < 0 ) { det = -det; }
    if ( det < min_det ) {
      min_det = det;
      axes[0] = tmp_axes[0];
      axes[1] = tmp_axes[1];
    }
  }
  if ( ! is_found ) { goto err; }
  
  get_transform_matrix( t_mat, axes );
  if ( mat_get_determinant_i3( t_mat ) < 0 ) {
    tmpval = axes[0];
    axes[0] = axes[1];
    axes[1] = tmpval;
  }

  return 1;

 err:
  return 0;
}
Ejemplo n.º 11
0
static int laue4mmm( int axes[3],
		     const Symmetry * symmetry )
{
  int i, is_found, tmpval, axis;
  int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3];
  int axis_vec[3];

  for ( i = 0; i < symmetry->size; i++ ) {
    get_proper_rotation( prop_rot, symmetry->rot[i] );

    /* Search foud-fold rotation */
    if ( mat_get_trace_i3( prop_rot ) == 1 ) {
      /* The first axis */
      axes[2] = get_rotation_axis( prop_rot );
      break;
    }
  }

  is_found = 0;
  for ( i = 0; i < symmetry->size; i++ ) {
    get_proper_rotation( prop_rot2, symmetry->rot[i] );

    /* Search two-fold rotation */
    if ( ! ( mat_get_trace_i3( prop_rot2 ) == -1 ) ) {
      continue;
    }

    /* The second axis */
    axis = get_rotation_axis( prop_rot2 );
    if ( ! ( axis == axes[2] ) ) {
      axes[0] = axis;
      is_found = 1;
      break;
    }
  }
  if ( ! is_found ) { goto err; }


  /* The third axis */
  mat_multiply_matrix_vector_i3( axis_vec, prop_rot, rot_axes[axes[0]] );
  is_found = 0;
  for ( i = 0; i < NUM_ROT_AXES; i++ ) {
    if ( is_exist_axis( axis_vec, i ) ) {
      is_found = 1;
      axes[1] = i;
      break;
    }
  }
  if ( ! is_found ) { goto err; }

  get_transform_matrix( t_mat, axes );
  if ( mat_get_determinant_i3( t_mat ) < 0 ) {
    tmpval = axes[0];
    axes[0] = axes[1];
    axes[1] = tmpval;
  }

  return 1;

 err:
  return 0;
}
Ejemplo n.º 12
0
static int get_ir_reciprocal_mesh(int grid_address[][3],
				  int map[],
				  const int mesh[3],
				  const int is_shift[3],
				  const MatINT *rot_reciprocal)
{
  /* In the following loop, mesh is doubled. */
  /* Even and odd mesh numbers correspond to */
  /* is_shift[i] are 0 or 1, respectively. */
  /* is_shift = [0,0,0] gives Gamma center mesh. */
  /* grid: reducible grid points */
  /* map: the mapping from each point to ir-point. */

  int i, j, k, l, grid_point, grid_point_rot, num_ir = 0;
  int address[3], address_double[3], address_double_rot[3];

  /* "-1" means the element is not touched yet. */
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    map[i] = -1;
  }

#ifndef GRID_ORDER_XYZ
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	address[0] = k;
	address[1] = j;
	address[2] = i;
#else
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
	address[0] = i;
	address[1] = j;
	address[2] = k;
#endif	
	for (l = 0; l < 3; l++) {
	  address_double[l] = address[l] * 2 + is_shift[l];
	}
	grid_point = get_grid_point_double_mesh(address_double, mesh);
	reduce_grid_address(grid_address[grid_point], address, mesh);

	for (l = 0; l < rot_reciprocal->size; l++) {
	  mat_multiply_matrix_vector_i3(address_double_rot,
					rot_reciprocal->mat[l],
					address_double);
	  grid_point_rot = get_grid_point_double_mesh(address_double_rot, mesh);

	  if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (map[grid_point_rot] > -1) {
	      map[grid_point] = map[grid_point_rot];
	      break;
	    }
	  }
	}
	
	if (map[grid_point] == -1) {
	  map[grid_point] = grid_point;
	  num_ir++;
	}
      }
    }
  }

  return num_ir;
}

static int
get_ir_reciprocal_mesh_openmp(int grid_address[][3],
			      int map[],
			      const int mesh[3],
			      const int is_shift[3],
			      const MatINT * rot_reciprocal)
{
  int i, j, grid_point, grid_point_rot, num_ir;
  int address[3], address_double[3], address_double_rot[3];

#pragma omp parallel for private(j, grid_point, grid_point_rot, address, address_double, address_double_rot)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
#ifndef GRID_ORDER_XYZ
    /* address[2] * mesh[0] * mesh[1] + address[1] * mesh[0] + address[0]; */
    address[0] = i % mesh[0];
    address[2] = i / (mesh[0] * mesh[1]);
    address[1] = (i - address[2] * mesh[0] * mesh[1]) / mesh[0];
#else
    /* address[0] * mesh[1] * mesh[2] + address[1] * mesh[2] + address[2]; */
    address[2] = i % mesh[2];
    address[0] = i / (mesh[1] * mesh[2]);
    address[1] = (i - address[0] * mesh[1] * mesh[2]) / mesh[2];
#endif	
    for (j = 0; j < 3; j++) {
      address_double[j] = address[j] * 2 + is_shift[j];
    }

    grid_point = get_grid_point_double_mesh(address_double, mesh);
    map[grid_point] = grid_point;
    reduce_grid_address(grid_address[grid_point], address, mesh);

    for (j = 0; j < rot_reciprocal->size; j++) {
      mat_multiply_matrix_vector_i3(address_double_rot,
				    rot_reciprocal->mat[j],
				    address_double);
      grid_point_rot = get_grid_point_double_mesh(address_double_rot, mesh);

      if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	if (grid_point_rot < map[grid_point]) {
	  map[grid_point] = grid_point_rot;
	}
      }
    }
  }

  num_ir = 0;

#pragma omp parallel for reduction(+:num_ir)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (map[i] == i) {
      num_ir++;
    }
  }
  
  return num_ir;
}

/* Relocate grid addresses to first Brillouin zone */
/* bz_grid_address[prod(mesh + 1)][3] */
/* bz_map[prod(mesh * 2)] */
static int relocate_BZ_grid_address(int bz_grid_address[][3],
				    int bz_map[],
				    SPGCONST int grid_address[][3],
				    const int mesh[3],
				    SPGCONST double rec_lattice[3][3],
				    const int is_shift[3])
{
  double tolerance, min_distance;
  double q_vector[3], distance[KPT_NUM_BZ_SEARCH_SPACE];
  int bzmesh[3], bz_address_double[3];
  int i, j, k, min_index, boundary_num_gp, total_num_gp, bzgp, gp;

  tolerance = get_tolerance_for_BZ_reduction(rec_lattice, mesh);
  for (i = 0; i < 3; i++) {
    bzmesh[i] = mesh[i] * 2;
  }
  for (i = 0; i < bzmesh[0] * bzmesh[1] * bzmesh[2]; i++) {
    bz_map[i] = -1;
  }
  
  boundary_num_gp = 0;
  total_num_gp = mesh[0] * mesh[1] * mesh[2];
  for (i = 0; i < total_num_gp; i++) {
    for (j = 0; j < KPT_NUM_BZ_SEARCH_SPACE; j++) {
      for (k = 0; k < 3; k++) {
	q_vector[k] = 
	  ((grid_address[i][k] + kpt_bz_search_space[j][k] * mesh[k]) * 2 +
	   is_shift[k]) / ((double)mesh[k]) / 2;
      }
      mat_multiply_matrix_vector_d3(q_vector, rec_lattice, q_vector);
      distance[j] = mat_norm_squared_d3(q_vector);
    }
    min_distance = distance[0];
    min_index = 0;
    for (j = 1; j < KPT_NUM_BZ_SEARCH_SPACE; j++) {
      if (distance[j] < min_distance) {
	min_distance = distance[j];
	min_index = j;
      }
    }

    for (j = 0; j < KPT_NUM_BZ_SEARCH_SPACE; j++) {
      if (distance[j] < min_distance + tolerance) {
	if (j == min_index) {
	  gp = i;
	} else {
	  gp = boundary_num_gp + total_num_gp;
	}
	
	for (k = 0; k < 3; k++) {
	  bz_grid_address[gp][k] = 
	    grid_address[i][k] + kpt_bz_search_space[j][k] * mesh[k];
	  bz_address_double[k] = bz_grid_address[gp][k] * 2 + is_shift[k];
	}
	bzgp = get_grid_point_double_mesh(bz_address_double, bzmesh);
	bz_map[bzgp] = gp;
	if (j != min_index) {
	  boundary_num_gp++;
	}
      }
    }
  }

  return boundary_num_gp + total_num_gp;
}

static double get_tolerance_for_BZ_reduction(SPGCONST double rec_lattice[3][3],
					     const int mesh[3])
{
  int i, j;
  double tolerance;
  double length[3];
  
  for (i = 0; i < 3; i++) {
    length[i] = 0;
    for (j = 0; j < 3; j++) {
      length[i] += rec_lattice[j][i] * rec_lattice[j][i];
    }
    length[i] /= mesh[i] * mesh[i];
  }
  tolerance = length[0];
  for (i = 1; i < 3; i++) {
    if (tolerance < length[i]) {
      tolerance = length[i];
    }
  }
  tolerance *= 0.01;
  
  return tolerance;
}
Ejemplo n.º 13
0
static int get_ir_reciprocal_mesh(int grid_points[][3],
				  int map[],
				  const int mesh[3],
				  const int is_shift[3],
				  SPGCONST PointSymmetry * point_symmetry)
{
  /* In the following loop, mesh is doubled. */
  /* Even and odd mesh numbers correspond to */
  /* is_shift[i] = 0 and 1, respectively. */
  /* is_shift = [0,0,0] gives Gamma center mesh. */
  /* grid: reducible grid points */
  /* map: the mapping from each point to ir-point. */

  int i, j, k, l, address, address_rot, num_ir = 0;
  int grid_double[3], grid_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

  /* "-1" means the element is not touched yet. */
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    map[i] = -1;
  }

#ifndef GRID_ORDER_XYZ
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	grid_double[0] = k * 2 + is_shift[0];
	grid_double[1] = j * 2 + is_shift[1];
	grid_double[2] = i * 2 + is_shift[2];
#else
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	grid_double[0] = i * 2 + is_shift[0];
  	grid_double[1] = j * 2 + is_shift[1];
  	grid_double[2] = k * 2 + is_shift[2];
#endif	

	address = grid_to_address(grid_double, mesh, is_shift);
	get_grid_points(grid_points[address], grid_double, mesh);

	for (l = 0; l < point_symmetry->size; l++) {
	  mat_multiply_matrix_vector_i3(grid_rot,
					point_symmetry->rot[l],	grid_double);
	  get_vector_modulo(grid_rot, mesh_double);
	  address_rot = grid_to_address(grid_rot, mesh, is_shift);

	  if (address_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (map[address_rot] > -1) {
	      map[address] = map[address_rot];
	      break;
	    }
	  }
	}
	
	if (map[address] == -1) {
	  map[address] = address;
	  num_ir++;
	}
      }
    }
  }

  return num_ir;
}

static int
get_ir_reciprocal_mesh_openmp(int grid_points[][3],
			      int map[],
			      const int mesh[3],
			      const int is_shift[3],
			      SPGCONST PointSymmetry * point_symmetry)
{
  int i, j, k, l, address, address_rot, num_ir;
  int grid_double[3], grid_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

#ifndef GRID_ORDER_XYZ
#pragma omp parallel for private(j, k, l, address, address_rot, grid_double, grid_rot)
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	grid_double[0] = k * 2 + is_shift[0];
	grid_double[1] = j * 2 + is_shift[1];
	grid_double[2] = i * 2 + is_shift[2];
#else
#pragma omp parallel for private(j, k, l, address, address_rot, grid_double, grid_rot)
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	grid_double[0] = i * 2 + is_shift[0];
  	grid_double[1] = j * 2 + is_shift[1];
  	grid_double[2] = k * 2 + is_shift[2];
#endif	

	address = grid_to_address(grid_double, mesh, is_shift);
	map[address] = address;
	get_grid_points(grid_points[address], grid_double, mesh);

	for (l = 0; l < point_symmetry->size; l++) {
	  mat_multiply_matrix_vector_i3(grid_rot,
					point_symmetry->rot[l],	grid_double);
	  get_vector_modulo(grid_rot, mesh_double);
	  address_rot = grid_to_address(grid_rot, mesh, is_shift);

	  if (address_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (address_rot < map[address]) {
	      map[address] = address_rot;
	    }
	  }
	}
      }
    }
  }

  num_ir = 0;

#pragma omp parallel for reduction(+:num_ir)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (map[i] == i) {
      num_ir++;
    }
  }
  
  return num_ir;
}

static int get_ir_triplets_at_q(int weights[],
				int grid_points[][3],
				int third_q[],
				const int grid_point,
				const int mesh[3],
				SPGCONST PointSymmetry * pointgroup)
{
  int i, j, num_grid, q_2, num_ir_q, num_ir_triplets, ir_address;
  int mesh_double[3], is_shift[3];
  int grid_double0[3], grid_double1[3], grid_double2[3];
  int *map_q, *ir_addresses, *weight_q;
  double tolerance;
  double stabilizer_q[1][3];
  PointSymmetry pointgroup_q;

  tolerance = 0.1 / (mesh[0] + mesh[1] + mesh[2]);

  num_grid = mesh[0] * mesh[1] * mesh[2];

  for (i = 0; i < 3; i++) {
    /* Only consider the gamma-point */
    is_shift[i] = 0;
    mesh_double[i] = mesh[i] * 2;
  }

  /* Search irreducible q-points (map_q) with a stabilizer */
  address_to_grid(grid_double0, grid_point, mesh, is_shift); /* q */
  for (i = 0; i < 3; i++) {
    stabilizer_q[0][i] = (double)grid_double0[i] / mesh_double[i];
  }

  pointgroup_q = get_point_group_reciprocal_with_q(pointgroup,
						   tolerance,
						   1,
						   stabilizer_q);
  map_q = (int*) malloc(sizeof(int) * num_grid);

#ifdef _OPENMP
  num_ir_q = get_ir_reciprocal_mesh_openmp(grid_points,
					   map_q,
					   mesh,
					   is_shift,
					   &pointgroup_q);
#else
  num_ir_q = get_ir_reciprocal_mesh(grid_points,
				    map_q,
				    mesh,
				    is_shift,
				    &pointgroup_q);
#endif

  ir_addresses = (int*) malloc(sizeof(int) * num_ir_q);
  weight_q = (int*) malloc(sizeof(int) * num_grid);
  num_ir_q = 0;
  for (i = 0; i < num_grid; i++) {
    if (map_q[i] == i) {
      ir_addresses[num_ir_q] = i;
      num_ir_q++;
    }
    weight_q[i] = 0;
    third_q[i] = -1;
    weights[i] = 0;
  }

  for (i = 0; i < num_grid; i++) {
    weight_q[map_q[i]]++;
  }

#pragma omp parallel for private(j, grid_double1, grid_double2)
  for (i = 0; i < num_ir_q; i++) {
    address_to_grid(grid_double1, ir_addresses[i], mesh, is_shift); /* q' */
    for (j = 0; j < 3; j++) { /* q'' */
      grid_double2[j] = - grid_double0[j] - grid_double1[j];
    }
    get_vector_modulo(grid_double2, mesh_double);
    third_q[ir_addresses[i]] = grid_to_address(grid_double2, mesh, is_shift);
  }

  num_ir_triplets = 0;
  for (i = 0; i < num_ir_q; i++) {
    ir_address = ir_addresses[i];
    q_2 = third_q[ir_address];
    if (weights[map_q[q_2]]) {
      weights[map_q[q_2]] += weight_q[ir_address];
    } else {
      weights[ir_address] = weight_q[ir_address];
      num_ir_triplets++;
    }
  }

  free(map_q);
  map_q = NULL;
  free(weight_q);
  weight_q = NULL;
  free(ir_addresses);
  ir_addresses = NULL;

  return num_ir_triplets;
}

static void set_grid_triplets_at_q(int triplets[][3],
				   const int q_grid_point,
				   SPGCONST int grid_points[][3],
				   const int third_q[],
				   const int weights[],
				   const int mesh[3])
{
  const int is_shift[3] = {0, 0, 0};
  int i, j, k, num_edge, edge_pos, num_ir;
  int grid_double[3][3], ex_mesh[3], ex_mesh_double[3];

  for (i = 0; i < 3; i++) {
    ex_mesh[i] = mesh[i] + (mesh[i] % 2 == 0);
    ex_mesh_double[i] = ex_mesh[i] * 2;
  }

  for (i = 0; i < 3; i++) {
    grid_double[0][i] = grid_points[q_grid_point][i] * 2;
  }

  num_ir = 0;

  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (weights[i] < 1) {
      continue;
    }

    for (j = 0; j < 3; j++) {
      grid_double[1][j] = grid_points[i][j] * 2;
      grid_double[2][j] = grid_points[third_q[i]][j] * 2;
    }

    for (j = 0; j < 3; j++) {
      num_edge = 0;
      edge_pos = -1;
      for (k = 0; k < 3; k++) {
	if (abs(grid_double[k][j]) == mesh[j]) {
	  num_edge++;
	  edge_pos = k;
	}
      }

      if (num_edge == 1) {
	grid_double[edge_pos][j] = 0;
	for (k = 0; k < 3; k++) {
	  if (k != edge_pos) {
	    grid_double[edge_pos][j] -= grid_double[k][j];
	  }
	}
      }
      if (num_edge == 2) {
	grid_double[edge_pos][j] = -grid_double[edge_pos][j];
      }
    }

    for (j = 0; j < 3; j++) {
      get_vector_modulo(grid_double[j], ex_mesh_double);
      triplets[num_ir][j] = grid_to_address(grid_double[j], ex_mesh, is_shift);
    }
    
    num_ir++;
  }

}

static int grid_to_address(const int grid_double[3],
			   const int mesh[3],
			   const int is_shift[3])
{
  int i, grid[3];

  for (i = 0; i < 3; i++) {
    if (grid_double[i] % 2 == 0 && (! is_shift[i]) ) {
      grid[i] = grid_double[i] / 2;
    } else {
      if (grid_double[i] % 2 != 0 && is_shift[i]) {
	grid[i] = (grid_double[i] - 1) / 2;
      } else {
	return -1;
      }
    }
  }

#ifndef GRID_ORDER_XYZ
  return grid[2] * mesh[0] * mesh[1] + grid[1] * mesh[0] + grid[0];
#else
  return grid[0] * mesh[1] * mesh[2] + grid[1] * mesh[2] + grid[2];
#endif  
}

static void address_to_grid(int grid_double[3],
			    const int address,
			    const int mesh[3],
			    const int is_shift[3])
{
  int i;
  int grid[3];

#ifndef GRID_ORDER_XYZ
  grid[2] = address / (mesh[0] * mesh[1]);
  grid[1] = (address - grid[2] * mesh[0] * mesh[1]) / mesh[0];
  grid[0] = address % mesh[0];
#else
  grid[0] = address / (mesh[1] * mesh[2]);
  grid[1] = (address - grid[0] * mesh[1] * mesh[2]) / mesh[2];
  grid[2] = address % mesh[2];
#endif

  for (i = 0; i < 3; i++) {
    grid_double[i] = grid[i] * 2 + is_shift[i];
  }
}

static void get_grid_points(int grid[3],
			    const int grid_double[3],
			    const int mesh[3])
{
  int i;

  for (i = 0; i < 3; i++) {
    if (grid_double[i] % 2 == 0) {
      grid[i] = grid_double[i] / 2;
    } else {
      grid[i] = (grid_double[i] - 1) / 2;
    }

#ifndef GRID_BOUNDARY_AS_NEGATIVE
    grid[i] = grid[i] - mesh[i] * (grid[i] > mesh[i] / 2);
#else
    grid[i] = grid[i] - mesh[i] * (grid[i] >= mesh[i] / 2);
#endif
  }  
}

static void get_vector_modulo(int v[3], const int m[3])
{
  int i;

  for (i = 0; i < 3; i++) {
    v[i] = v[i] % m[i];

    if (v[i] < 0)
      v[i] += m[i];
  }
}
Ejemplo n.º 14
0
static int get_ir_reciprocal_mesh(int grid_address[][3],
				  int map[],
				  const int mesh[3],
				  const int is_shift[3],
				  const MatINT *rot_reciprocal)
{
  /* In the following loop, mesh is doubled. */
  /* Even and odd mesh numbers correspond to */
  /* is_shift[i] are 0 or 1, respectively. */
  /* is_shift = [0,0,0] gives Gamma center mesh. */
  /* grid: reducible grid points */
  /* map: the mapping from each point to ir-point. */

  int i, j, k, l, grid_point, grid_point_rot, num_ir = 0;
  int address_double[3], address_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

  /* "-1" means the element is not touched yet. */
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    map[i] = -1;
  }

#ifndef GRID_ORDER_XYZ
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	address_double[0] = k * 2 + is_shift[0];
	address_double[1] = j * 2 + is_shift[1];
	address_double[2] = i * 2 + is_shift[2];
#else
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	address_double[0] = i * 2 + is_shift[0];
  	address_double[1] = j * 2 + is_shift[1];
  	address_double[2] = k * 2 + is_shift[2];
#endif	

	grid_point = get_grid_point_double_mesh(address_double, mesh);
	get_grid_address(grid_address[grid_point], address_double, mesh);

	for (l = 0; l < rot_reciprocal->size; l++) {
	  mat_multiply_matrix_vector_i3(address_rot,
					rot_reciprocal->mat[l],
					address_double);
	  get_vector_modulo(address_rot, mesh_double);
	  grid_point_rot = get_grid_point_double_mesh(address_rot, mesh);

	  if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (map[grid_point_rot] > -1) {
	      map[grid_point] = map[grid_point_rot];
	      break;
	    }
	  }
	}
	
	if (map[grid_point] == -1) {
	  map[grid_point] = grid_point;
	  num_ir++;
	}
      }
    }
  }

  return num_ir;
}

static int
get_ir_reciprocal_mesh_openmp(int grid_address[][3],
			      int map[],
			      const int mesh[3],
			      const int is_shift[3],
			      const MatINT * rot_reciprocal)
{
  int i, j, k, l, grid_point, grid_point_rot, num_ir;
  int address_double[3], address_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

#ifndef GRID_ORDER_XYZ
#pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, address_double, address_rot)
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	address_double[0] = k * 2 + is_shift[0];
	address_double[1] = j * 2 + is_shift[1];
	address_double[2] = i * 2 + is_shift[2];
#else
#pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, address_double, address_rot)
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	address_double[0] = i * 2 + is_shift[0];
  	address_double[1] = j * 2 + is_shift[1];
  	address_double[2] = k * 2 + is_shift[2];
#endif	

	grid_point = get_grid_point_double_mesh(address_double, mesh);
	map[grid_point] = grid_point;
	get_grid_address(grid_address[grid_point], address_double, mesh);

	for (l = 0; l < rot_reciprocal->size; l++) {
	  mat_multiply_matrix_vector_i3(address_rot,
					rot_reciprocal->mat[l],
					address_double);
	  get_vector_modulo(address_rot, mesh_double);
	  grid_point_rot = get_grid_point_double_mesh(address_rot, mesh);

	  if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (grid_point_rot < map[grid_point]) {
	      map[grid_point] = grid_point_rot;
	    }
	  }
	}
      }
    }
  }

  num_ir = 0;

#pragma omp parallel for reduction(+:num_ir)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (map[i] == i) {
      num_ir++;
    }
  }
  
  return num_ir;
}

/* Relocate grid addresses to first Brillouin zone */
/* bz_grid_address[prod(mesh + 1)][3] */
/* bz_map[prod(mesh * 2)] */
static int relocate_BZ_grid_address(int bz_grid_address[][3],
				    int bz_map[],
				    SPGCONST int grid_address[][3],
				    const int mesh[3],
				    SPGCONST double rec_lattice[3][3],
				    const int is_shift[3])
{
  double tolerance, min_distance;
  double q_vector[3], distance[NUM_DIM_SEARCH];
  int bzmesh[3], bzmesh_double[3], bz_address_double[3];
  int i, j, k, min_index, boundary_num_gp, total_num_gp, bzgp, gp;

  tolerance = get_tolerance_for_BZ_reduction(rec_lattice, mesh);
  for (i = 0; i < 3; i++) {
    bzmesh[i] = mesh[i] * 2;
    bzmesh_double[i] = bzmesh[i] * 2;
  }
  for (i = 0; i < bzmesh[0] * bzmesh[1] * bzmesh[2]; i++) {
    bz_map[i] = -1;
  }
  
  boundary_num_gp = 0;
  total_num_gp = mesh[0] * mesh[1] * mesh[2];
  for (i = 0; i < total_num_gp; i++) {
    for (j = 0; j < NUM_DIM_SEARCH; j++) {
      for (k = 0; k < 3; k++) {
	q_vector[k] = 
	  ((grid_address[i][k] + search_space[j][k] * mesh[k]) * 2 +
	   is_shift[k]) / ((double)mesh[k]) / 2;
      }
      mat_multiply_matrix_vector_d3(q_vector, rec_lattice, q_vector);
      distance[j] = mat_norm_squared_d3(q_vector);
    }
    min_distance = distance[0];
    min_index = 0;
    for (j = 1; j < NUM_DIM_SEARCH; j++) {
      if (distance[j] < min_distance) {
	min_distance = distance[j];
	min_index = j;
      }
    }

    for (j = 0; j < NUM_DIM_SEARCH; j++) {
      if (distance[j] < min_distance + tolerance) {
	if (j == min_index) {
	  gp = i;
	} else {
	  gp = boundary_num_gp + total_num_gp;
	}
	
	for (k = 0; k < 3; k++) {
	  bz_grid_address[gp][k] = 
	    grid_address[i][k] + search_space[j][k] * mesh[k];
	  bz_address_double[k] = bz_grid_address[gp][k] * 2 + is_shift[k];
	}
	get_vector_modulo(bz_address_double, bzmesh_double);
	bzgp = get_grid_point_double_mesh(bz_address_double, bzmesh);
	bz_map[bzgp] = gp;
	if (j != min_index) {
	  boundary_num_gp++;
	}
      }
    }
  }

  return boundary_num_gp + total_num_gp;
}

static double get_tolerance_for_BZ_reduction(SPGCONST double rec_lattice[3][3],
					     const int mesh[3])
{
  int i, j;
  double tolerance;
  double length[3];
  
  for (i = 0; i < 3; i++) {
    length[i] = 0;
    for (j = 0; j < 3; j++) {
      length[i] += rec_lattice[j][i] * rec_lattice[j][i];
    }
    length[i] /= mesh[i] * mesh[i];
  }
  tolerance = length[0];
  for (i = 1; i < 3; i++) {
    if (tolerance < length[i]) {
      tolerance = length[i];
    }
  }
  tolerance *= 0.01;
  
  return tolerance;
}
 
static int get_ir_triplets_at_q(int map_triplets[],
				int map_q[],
				int grid_address[][3],
				const int grid_point,
				const int mesh[3],
				const MatINT * rot_reciprocal)
{
  int i, j, num_grid, q_2, num_ir_q, num_ir_triplets, ir_grid_point;
  int mesh_double[3], is_shift[3];
  int address_double0[3], address_double1[3], address_double2[3];
  int *ir_grid_points, *third_q;
  double tolerance;
  double stabilizer_q[1][3];
  MatINT *rot_reciprocal_q;

  tolerance = 0.01 / (mesh[0] + mesh[1] + mesh[2]);
  num_grid = mesh[0] * mesh[1] * mesh[2];

  for (i = 0; i < 3; i++) {
    /* Only consider the gamma-point */
    is_shift[i] = 0;
    mesh_double[i] = mesh[i] * 2;
  }

  /* Search irreducible q-points (map_q) with a stabilizer */
  /* q */  
  grid_point_to_address_double(address_double0, grid_point, mesh, is_shift);
  for (i = 0; i < 3; i++) {
    stabilizer_q[0][i] =
      (double)address_double0[i] / mesh_double[i] - (address_double0[i] > mesh[i]);
  }

  rot_reciprocal_q = get_point_group_reciprocal_with_q(rot_reciprocal,
						       tolerance,
						       1,
						       stabilizer_q);
#ifdef _OPENMP
  num_ir_q = get_ir_reciprocal_mesh_openmp(grid_address,
					   map_q,
					   mesh,
					   is_shift,
					   rot_reciprocal_q);
#else
  num_ir_q = get_ir_reciprocal_mesh(grid_address,
				    map_q,
				    mesh,
				    is_shift,
				    rot_reciprocal_q);
#endif
  mat_free_MatINT(rot_reciprocal_q);

  third_q = (int*) malloc(sizeof(int) * num_ir_q);
  ir_grid_points = (int*) malloc(sizeof(int) * num_ir_q);
  num_ir_q = 0;
  for (i = 0; i < num_grid; i++) {
    if (map_q[i] == i) {
      ir_grid_points[num_ir_q] = i;
      num_ir_q++;
    }
    map_triplets[i] = -1;
  }

#pragma omp parallel for private(j, address_double1, address_double2)
  for (i = 0; i < num_ir_q; i++) {
    grid_point_to_address_double(address_double1,
				 ir_grid_points[i],
				 mesh,
				 is_shift); /* q' */
    for (j = 0; j < 3; j++) { /* q'' */
      address_double2[j] = - address_double0[j] - address_double1[j];
    }
    get_vector_modulo(address_double2, mesh_double);
    third_q[i] = get_grid_point_double_mesh(address_double2, mesh);
  }

  num_ir_triplets = 0;
  for (i = 0; i < num_ir_q; i++) {
    ir_grid_point = ir_grid_points[i];
    q_2 = third_q[i];
    if (map_triplets[map_q[q_2]] > -1) {
      map_triplets[ir_grid_point] = map_q[q_2];
    } else {
      map_triplets[ir_grid_point] = ir_grid_point;
      num_ir_triplets++;
    }
  }

#pragma omp parallel for
  for (i = 0; i < num_grid; i++) {
    map_triplets[i] = map_triplets[map_q[i]];
  }
  
  free(third_q);
  third_q = NULL;
  free(ir_grid_points);
  ir_grid_points = NULL;

  return num_ir_triplets;
}

static int get_BZ_triplets_at_q(int triplets[][3],
				const int grid_point,
				SPGCONST int bz_grid_address[][3],
				const int bz_map[],
				const int map_triplets[],
				const int num_map_triplets,
				const int mesh[3])
{
  int i, j, k, num_ir;
  int bz_address[3][3], bz_address_double[3], bzmesh[3], bzmesh_double[3];
  int *ir_grid_points;

  for (i = 0; i < 3; i++) {
    bzmesh[i] = mesh[i] * 2;
    bzmesh_double[i] = bzmesh[i] * 2;
  }

  num_ir = 0;
  ir_grid_points = (int*) malloc(sizeof(int) * num_map_triplets);
  for (i = 0; i < num_map_triplets; i++) {
    if (map_triplets[i] == i) {
      ir_grid_points[num_ir] = i;
      num_ir++;
    }
  }
 
#pragma omp parallel for private(j, k, bz_address, bz_address_double)
  for (i = 0; i < num_ir; i++) {
    for (j = 0; j < 3; j++) {
      bz_address[0][j] = bz_grid_address[grid_point][j];
      bz_address[1][j] = bz_grid_address[ir_grid_points[i]][j];
      bz_address[2][j] = - bz_address[0][j] - bz_address[1][j];
    }
    for (j = 2; j > -1; j--) {
      if (get_third_q_of_triplets_at_q(bz_address,
    				       j,
    				       bz_map,
    				       mesh,
    				       bzmesh,
    				       bzmesh_double) == 0) {
    	break;
      }
    }
    for (j = 0; j < 3; j++) {
      for (k = 0; k < 3; k++) {
	bz_address_double[k] = bz_address[j][k] * 2;
      }
      get_vector_modulo(bz_address_double, bzmesh_double);
      triplets[i][j] =
	bz_map[get_grid_point_double_mesh(bz_address_double, bzmesh)];
    }
  }

  free(ir_grid_points);
  
  return num_ir;
}

static int get_third_q_of_triplets_at_q(int bz_address[3][3],
					const int q_index,
					const int bz_map[],
					const int mesh[3],
					const int bzmesh[3],
					const int bzmesh_double[3])
{
  int i, j, smallest_g, smallest_index, sum_g, delta_g[3];
  int bzgp[NUM_DIM_SEARCH], bz_address_double[3];

  get_vector_modulo(bz_address[q_index], mesh);
  for (i = 0; i < 3; i++) {
    delta_g[i] = 0;
    for (j = 0; j < 3; j++) {
      delta_g[i] += bz_address[j][i];
    }
    delta_g[i] /= mesh[i];
  }
  
  for (i = 0; i < NUM_DIM_SEARCH; i++) {
    for (j = 0; j < 3; j++) {
      bz_address_double[j] = (bz_address[q_index][j] +
			   search_space[i][j] * mesh[j]) * 2;
    }
    for (j = 0; j < 3; j++) {
      if (bz_address_double[j] < 0) {
	bz_address_double[j] += bzmesh_double[j];
      }
    }
    get_vector_modulo(bz_address_double, bzmesh_double);
    bzgp[i] = bz_map[get_grid_point_double_mesh(bz_address_double, bzmesh)];
  }

  for (i = 0; i < NUM_DIM_SEARCH; i++) {
    if (bzgp[i] != -1) {
      goto escape;
    }
  }
  warning_print("******* Warning *******\n");
  warning_print(" No third-q was found.\n");
  warning_print("******* Warning *******\n");

 escape:

  smallest_g = 4;
  smallest_index = 0;

  for (i = 0; i < NUM_DIM_SEARCH; i++) {
    if (bzgp[i] > -1) { /* q'' is in BZ */
      sum_g = (abs(delta_g[0] + search_space[i][0]) +
	       abs(delta_g[1] + search_space[i][1]) +
	       abs(delta_g[2] + search_space[i][2]));
      if (sum_g < smallest_g) {
	smallest_index = i;
	smallest_g = sum_g;
      }
    }
  }

  for (i = 0; i < 3; i++) {
    bz_address[q_index][i] += search_space[smallest_index][i] * mesh[i];
  }

  return smallest_g;
}
Ejemplo n.º 15
0
static int get_ir_reciprocal_mesh(int grid_address[][3],
				  int map[],
				  const int mesh[3],
				  const int is_shift[3],
				  SPGCONST PointSymmetry * point_symmetry)
{
  /* In the following loop, mesh is doubled. */
  /* Even and odd mesh numbers correspond to */
  /* is_shift[i] = 0 and 1, respectively. */
  /* is_shift = [0,0,0] gives Gamma center mesh. */
  /* grid: reducible grid points */
  /* map: the mapping from each point to ir-point. */

  int i, j, k, l, grid_point, grid_point_rot, num_ir = 0;
  int grid_double[3], grid_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

  /* "-1" means the element is not touched yet. */
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    map[i] = -1;
  }

#ifndef GRID_ORDER_XYZ
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	grid_double[0] = k * 2 + is_shift[0];
	grid_double[1] = j * 2 + is_shift[1];
	grid_double[2] = i * 2 + is_shift[2];
#else
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	grid_double[0] = i * 2 + is_shift[0];
  	grid_double[1] = j * 2 + is_shift[1];
  	grid_double[2] = k * 2 + is_shift[2];
#endif	

	grid_point = get_grid_point(grid_double, mesh);
	get_grid_address(grid_address[grid_point], grid_double, mesh);

	for (l = 0; l < point_symmetry->size; l++) {
	  mat_multiply_matrix_vector_i3(grid_rot,
					point_symmetry->rot[l],	grid_double);
	  get_vector_modulo(grid_rot, mesh_double);
	  grid_point_rot = get_grid_point(grid_rot, mesh);

	  if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (map[grid_point_rot] > -1) {
	      map[grid_point] = map[grid_point_rot];
	      break;
	    }
	  }
	}
	
	if (map[grid_point] == -1) {
	  map[grid_point] = grid_point;
	  num_ir++;
	}
      }
    }
  }

  return num_ir;
}

static int
get_ir_reciprocal_mesh_openmp(int grid_address[][3],
			      int map[],
			      const int mesh[3],
			      const int is_shift[3],
			      SPGCONST PointSymmetry * point_symmetry)
{
  int i, j, k, l, grid_point, grid_point_rot, num_ir;
  int grid_double[3], grid_rot[3], mesh_double[3];

  for (i = 0; i < 3; i++) {
    mesh_double[i] = mesh[i] * 2;
  }

#ifndef GRID_ORDER_XYZ
#pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, grid_double, grid_rot)
  for (i = 0; i < mesh[2]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[0]; k++) {
	grid_double[0] = k * 2 + is_shift[0];
	grid_double[1] = j * 2 + is_shift[1];
	grid_double[2] = i * 2 + is_shift[2];
#else
#pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, grid_double, grid_rot)
  for (i = 0; i < mesh[0]; i++) {
    for (j = 0; j < mesh[1]; j++) {
      for (k = 0; k < mesh[2]; k++) {
  	grid_double[0] = i * 2 + is_shift[0];
  	grid_double[1] = j * 2 + is_shift[1];
  	grid_double[2] = k * 2 + is_shift[2];
#endif	

	grid_point = get_grid_point(grid_double, mesh);
	map[grid_point] = grid_point;
	get_grid_address(grid_address[grid_point], grid_double, mesh);

	for (l = 0; l < point_symmetry->size; l++) {
	  mat_multiply_matrix_vector_i3(grid_rot,
					point_symmetry->rot[l],	grid_double);
	  get_vector_modulo(grid_rot, mesh_double);
	  grid_point_rot = get_grid_point(grid_rot, mesh);

	  if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */
	    if (grid_point_rot < map[grid_point]) {
	      map[grid_point] = grid_point_rot;
	    }
	  }
	}
      }
    }
  }

  num_ir = 0;

#pragma omp parallel for reduction(+:num_ir)
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (map[i] == i) {
      num_ir++;
    }
  }
  
  return num_ir;
}

/* Relocate grid addresses to first Brillouin zone */
/* bz_grid_address[prod(mesh + 1)][3] */
/* bz_map[prod(mesh * 2 - 1)] */
static int relocate_BZ_grid_address(int bz_grid_address[][3],
				    int bz_map[],
				    int grid_address[][3],
				    const int mesh[3],
				    SPGCONST double rec_lattice[3][3],
				    const int is_shift[3])
{
  double tolerance, min_distance;
  double vector[3], distance[27];
  int bzmesh[3], bzmesh_double[3], address_double[3];
  int i, j, k, min_index, boundary_gp, total_num_gp, bzgp, gp;

  tolerance = get_tolerance_for_BZ_reduction(rec_lattice);
  for (i = 0; i < 3; i++) {
    bzmesh[i] = mesh[i] * 2 - 1;
    bzmesh_double[i] = bzmesh[i] * 2;
  }
  for (i = 0; i < bzmesh[0] * bzmesh[1] * bzmesh[2]; i++) {
    bz_map[i] = -1;
  }
  
  boundary_gp = 0;
  total_num_gp = mesh[0] * mesh[1] * mesh[2];
  for (i = 0; i < total_num_gp; i++) {
    for (j = 0; j < 27; j++) {
      for (k = 0; k < 3; k++) {
	address_double[k] =
	  (grid_address[i][k] + search_space[j][k] * mesh[k]) * 2 + is_shift[k];
      }
      mat_multiply_matrix_vector_di3(vector, rec_lattice, address_double);
      distance[j] = mat_norm_squared_d3(vector);
    }
    min_distance = distance[0];
    min_index = 0;
    for (j = 1; j < 27; j++) {
      if (distance[j] + tolerance < min_distance) {
	min_distance = distance[j];
	min_index = j;
      }
    }

    for (j = 0; j < 27; j++) {
      if (distance[j] < min_distance + tolerance) {
	if (j == min_index) {
	  gp = i;
	} else {
	  gp = boundary_gp + total_num_gp;
	}
	for (k = 0; k < 3; k++) {
	  bz_grid_address[gp][k] = 
	    grid_address[i][k] + search_space[j][k] * mesh[k];
	  address_double[k] = bz_grid_address[gp][k] * 2 + is_shift[k];
	  if (address_double[k] < 0) {
	    address_double[k] += bzmesh_double[k];
	  }
	}
	bzgp = get_grid_point(address_double, bzmesh);
	bz_map[bzgp] = gp;
	if (j != min_index) {
	  boundary_gp++;
	}
      }
    }
  }

  return boundary_gp + total_num_gp;
}

static double get_tolerance_for_BZ_reduction(SPGCONST double rec_lattice[3][3])
{
  int i, j;
  double tolerance;
  double length[3];
  
  for (i = 0; i < 3; i++) {
    length[i] = 0;
    for (j = 0; j < 3; j++) {
      length[i] += rec_lattice[j][i] * rec_lattice[j][i];
    }
  }
  tolerance = length[0];
  for (i = 1; i < 3; i++) {
    if (tolerance > length[i]) {
      tolerance = length[i];
    }
  }
  tolerance /= 100;
  return tolerance;
}
 
static int get_ir_triplets_at_q(int weights[],
				int grid_address[][3],
				int third_q[],
				const int grid_point,
				const int mesh[3],
				SPGCONST PointSymmetry * pointgroup)
{
  int i, j, num_grid, q_2, num_ir_q, num_ir_triplets, ir_grid_point;
  int mesh_double[3], is_shift[3];
  int grid_double0[3], grid_double1[3], grid_double2[3];
  int *map_q, *ir_grid_points, *weight_q;
  double tolerance;
  double stabilizer_q[1][3];
  PointSymmetry pointgroup_q;

  tolerance = 0.1 / (mesh[0] + mesh[1] + mesh[2]);

  num_grid = mesh[0] * mesh[1] * mesh[2];

  for (i = 0; i < 3; i++) {
    /* Only consider the gamma-point */
    is_shift[i] = 0;
    mesh_double[i] = mesh[i] * 2;
  }

  /* Search irreducible q-points (map_q) with a stabilizer */
  grid_point_to_grid_double(grid_double0, grid_point, mesh, is_shift); /* q */
  for (i = 0; i < 3; i++) {
    stabilizer_q[0][i] =
      (double)grid_double0[i] / mesh_double[i] - (grid_double0[i] > mesh[i]);
  }

  pointgroup_q = get_point_group_reciprocal_with_q(pointgroup,
						   tolerance,
						   1,
						   stabilizer_q);
  map_q = (int*) malloc(sizeof(int) * num_grid);

#ifdef _OPENMP
  num_ir_q = get_ir_reciprocal_mesh_openmp(grid_address,
					   map_q,
					   mesh,
					   is_shift,
					   &pointgroup_q);
#else
  num_ir_q = get_ir_reciprocal_mesh(grid_address,
				    map_q,
				    mesh,
				    is_shift,
				    &pointgroup_q);
#endif

  ir_grid_points = (int*) malloc(sizeof(int) * num_ir_q);
  weight_q = (int*) malloc(sizeof(int) * num_grid);
  num_ir_q = 0;
  for (i = 0; i < num_grid; i++) {
    if (map_q[i] == i) {
      ir_grid_points[num_ir_q] = i;
      num_ir_q++;
    }
    weight_q[i] = 0;
    third_q[i] = -1;
    weights[i] = 0;
  }

  for (i = 0; i < num_grid; i++) {
    weight_q[map_q[i]]++;
  }

#pragma omp parallel for private(j, grid_double1, grid_double2)
  for (i = 0; i < num_ir_q; i++) {
    grid_point_to_grid_double(grid_double1, ir_grid_points[i], mesh, is_shift); /* q' */
    for (j = 0; j < 3; j++) { /* q'' */
      grid_double2[j] = - grid_double0[j] - grid_double1[j];
    }
    get_vector_modulo(grid_double2, mesh_double);
    third_q[ir_grid_points[i]] = get_grid_point(grid_double2, mesh);
  }

  num_ir_triplets = 0;
  for (i = 0; i < num_ir_q; i++) {
    ir_grid_point = ir_grid_points[i];
    q_2 = third_q[ir_grid_point];
    if (weights[map_q[q_2]]) {
      weights[map_q[q_2]] += weight_q[ir_grid_point];
    } else {
      weights[ir_grid_point] = weight_q[ir_grid_point];
      num_ir_triplets++;
    }
  }

  free(map_q);
  map_q = NULL;
  free(weight_q);
  weight_q = NULL;
  free(ir_grid_points);
  ir_grid_points = NULL;

  return num_ir_triplets;
}

static int get_BZ_triplets_at_q(int triplets[][3],
				const int grid_point,
				SPGCONST int bz_grid_address[][3],
				const int bz_map[],
				const int weights[],
				const int mesh[3])
{
  int i, j, k, num_ir;
  int address[3][3], address_double[3], bzmesh[3], bzmesh_double[3];
  int *ir_grid_points;

  for (i = 0; i < 3; i++) {
    bzmesh[i] = mesh[i] * 2 - 1;
    bzmesh_double[i] = bzmesh[i] * 2;
  }

  num_ir = 0;
  ir_grid_points = (int*) malloc(sizeof(int) * mesh[0] * mesh[1] * mesh[2]);
  for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) {
    if (weights[i] > 0) {
      ir_grid_points[num_ir] = i;
      num_ir++;
    }
  }
 
#pragma omp parallel for private(j, k, address, address_double)
  for (i = 0; i < num_ir; i++) {
    for (j = 0; j < 3; j++) {
      address[0][j] = bz_grid_address[grid_point][j];
      address[1][j] = bz_grid_address[ir_grid_points[i]][j];
      address[2][j] = - address[0][j] - address[1][j];
    }
    get_third_q_of_triplets_at_q(address,
				 bz_map,
				 mesh,
				 bzmesh,
				 bzmesh_double);
    for (j = 0; j < 3; j++) {
      for (k = 0; k < 3; k++) {
	address_double[k] = address[j][k] * 2;
	if (address_double[k] < 0) {
	  address_double[k] += bzmesh_double[k];
	}
      }
      triplets[i][j] = bz_map[get_grid_point(address_double, bzmesh)];
    }
  }

  free(ir_grid_points);
  
  return num_ir;
}

static void get_third_q_of_triplets_at_q(int address[3][3],
					 const int bz_map[],
					 const int mesh[3],
					 const int bzmesh[3],
					 const int bzmesh_double[3])
{
  int i, j, smallest_g, smallest_index, sum_g, delta_g[3];
  int bzgp[27], address_double[3];

  get_vector_modulo(address[2], mesh);
  for (i = 0; i < 3; i++) {
    delta_g[i] = 0;
    for (j = 0; j < 3; j++) {
      delta_g[i] += address[j][i];
    }
    delta_g[i] /= mesh[i];
  }
  
  for (i = 0; i < 27; i++) {
    for (j = 0; j < 3; j++) {
      address_double[j] = (address[2][j] + search_space[i][j] * mesh[j]) * 2;
    }
    if (abs(address_double[0] > bzmesh[0]) ||
	abs(address_double[1] > bzmesh[1]) ||
	abs(address_double[2] > bzmesh[2]) ||
	abs(address_double[0] < -bzmesh[0]) ||
	abs(address_double[1] < -bzmesh[1]) ||
	abs(address_double[2] < -bzmesh[2])) { /* outside extended zone */
      bzgp[i] = -1;
      continue;
    }
    for (j = 0; j < 3; j++) {
      if (address_double[j] < 0) {
	address_double[j] += bzmesh_double[j];
      }
    }
    bzgp[i] = bz_map[get_grid_point(address_double, bzmesh)];
  }

  for (i = 0; i < 27; i++) {
    if (bzgp[i] != -1) {
      goto escape;
    }
  }
  printf("******* Warning *******\n");
  printf(" No third-q was found.\n");
  printf("******* Warning *******\n");

 escape:

  smallest_g = 4;
  smallest_index = 0;
  for (i = 0; i < 27; i++) {
    if (bzgp[i] > -1) { /* q'' is in BZ */
      sum_g = (abs(delta_g[0] + search_space[i][0]) +
	       abs(delta_g[1] + search_space[i][1]) +
	       abs(delta_g[2] + search_space[i][2]));
      if (sum_g < smallest_g) {
	smallest_index = i;
	smallest_g = sum_g;
      }
    }
  }
  
  for (i = 0; i < 3; i++) {
    address[2][i] += search_space[smallest_index][i] * mesh[i];
  }
}