Example #1
0
static Cell * get_cell_with_smallest_lattice( SPGCONST Cell * cell,
					      const double symprec )
{
  int i, j;
  double min_lat[3][3], trans_mat[3][3], inv_lat[3][3];
  Cell * smallest_cell;

  if ( lat_smallest_lattice_vector( min_lat,
				    cell->lattice,
				    symprec ) ) {
    mat_inverse_matrix_d3( inv_lat, min_lat, 0 );
    mat_multiply_matrix_d3( trans_mat, inv_lat, cell->lattice );
    smallest_cell = cel_alloc_cell( cell->size );
    mat_copy_matrix_d3( smallest_cell->lattice, min_lat );
    for ( i = 0; i < cell->size; i++ ) {
      smallest_cell->types[i] = cell->types[i];
      mat_multiply_matrix_vector_d3( smallest_cell->position[i],
				     trans_mat, cell->position[i] );
      for ( j = 0; j < 3; j++ ) {
	cell->position[i][j] -= mat_Nint( cell->position[i][j] );
      }
    }
  } else {
    smallest_cell = cel_alloc_cell( -1 );
  }

  return smallest_cell;
}
Example #2
0
/* Return NULL if failed */
static VecDBL *
translate_atoms_in_trimmed_lattice(const Cell * cell,
                                   SPGCONST double trimmed_lattice[3][3])
{
  int i, j;
  double tmp_matrix[3][3], axis_inv[3][3];
  VecDBL * position;

  position = NULL;

  if ((position = mat_alloc_VecDBL(cell->size)) == NULL) {
    return NULL;
  }

  mat_inverse_matrix_d3(tmp_matrix, trimmed_lattice, 0);
  mat_multiply_matrix_d3(axis_inv, tmp_matrix, cell->lattice);

  /* Send atoms into the trimmed cell */
  for (i = 0; i < cell->size; i++) {
    mat_multiply_matrix_vector_d3(position->vec[i],
                                  axis_inv,
                                  cell->position[i]);
    for (j = 0; j < 3; j++) {
      position->vec[i][j] = mat_Dmod1(position->vec[i][j]);
    }
  }

  return position;
}
Example #3
0
/* Acta Cryst. (2002). A58, 60-65 */
static void get_exact_location(double position[3],
			       SPGCONST Symmetry * conv_sym,
			       SPGCONST double bravais_lattice[3][3],
			       const double symprec)
{
  int i, j, k, num_sum;
  double sum_rot[3][3];
  double pos[3], sum_trans[3];

  debug_print("get_exact_location\n");

  num_sum = 0;
  for (i = 0; i < 3; i++) {
    sum_trans[i] = 0.0;
    for (j = 0; j < 3; j++) {
      sum_rot[i][j] = 0;
    }
  }
  
  for (i = 0; i < conv_sym->size; i++) {
    mat_multiply_matrix_vector_id3(pos,
				   conv_sym->rot[i],
				   position);
    for (j = 0; j < 3; j++) {
      pos[j] += conv_sym->trans[i][j];
    }

    if (cel_is_overlap(pos,
		       position,
		       bravais_lattice,
		       symprec)) {
      for (j = 0; j < 3; j++) {
	sum_trans[j] += conv_sym->trans[i][j] - 
	  mat_Nint(pos[j] - position[j]);
	for (k = 0; k < 3; k++) {
	  sum_rot[j][k] += conv_sym->rot[i][j][k];
	}
      }
      num_sum++;
    }
  }

  for (i = 0; i < 3; i++) {
    sum_trans[i] /= num_sum;
    for (j = 0; j < 3; j++) {
      sum_rot[i][j] /= num_sum;
    }
  }

  /* (sum_rot|sum_trans) is the special-position operator. */
  /* Elements of sum_rot can be fractional values. */
  mat_multiply_matrix_vector_d3(position,
				sum_rot,
				position);

  for (i = 0; i < 3; i++) {
    position[i] += sum_trans[i];
  }

}
Example #4
0
static VecDBL * get_positions_primitive( SPGCONST Cell * cell,
					 SPGCONST double prim_lat[3][3] )
{
  int i, j;
  double tmp_matrix[3][3], axis_inv[3][3];
  VecDBL * position;

  position = mat_alloc_VecDBL( cell->size );

  mat_inverse_matrix_d3(tmp_matrix, prim_lat, 0);
  mat_multiply_matrix_d3(axis_inv, tmp_matrix, cell->lattice);

  /* Send atoms into the primitive cell */
  debug_print("Positions in new axes reduced to primitive cell\n");
  for (i = 0; i < cell->size; i++) {
    mat_multiply_matrix_vector_d3( position->vec[i],
				   axis_inv, cell->position[i] );
    for (j = 0; j < 3; j++) {
      position->vec[i][j] -= mat_Nint( position->vec[i][j] );
    }
    debug_print("%d: %f %f %f\n", i + 1,
		position->vec[i][0], 
		position->vec[i][1],
		position->vec[i][2]);
  }

  return position;
}
Example #5
0
/* Return NULL if failed */
static VecDBL * get_positions_primitive(SPGCONST Cell * cell,
                                        SPGCONST double prim_lat[3][3])
{
    int i, j;
    double tmp_matrix[3][3], axis_inv[3][3];
    VecDBL * position;

    position = NULL;

    if ((position = mat_alloc_VecDBL(cell->size)) == NULL) {
        return NULL;
    }

    mat_inverse_matrix_d3(tmp_matrix, prim_lat, 0);
    mat_multiply_matrix_d3(axis_inv, tmp_matrix, cell->lattice);

    /* Send atoms into the primitive cell */
    for (i = 0; i < cell->size; i++) {
        mat_multiply_matrix_vector_d3(position->vec[i],
                                      axis_inv,
                                      cell->position[i]);
        for (j = 0; j < 3; j++) {
            position->vec[i][j] -= mat_Nint(position->vec[i][j]);
        }
    }

    return position;
}
Example #6
0
static Cell * get_conventional_primitive(SPGCONST Spacegroup * spacegroup,
        SPGCONST Cell * primitive)
{
    int i, j;
    double inv_brv[3][3], trans_mat[3][3];
    Cell * conv_prim;

    conv_prim = cel_alloc_cell(primitive->size);

    mat_inverse_matrix_d3(inv_brv, spacegroup->bravais_lattice, 0);
    mat_multiply_matrix_d3(trans_mat, inv_brv, primitive->lattice);

    for (i = 0; i < primitive->size; i++) {
        conv_prim->types[i] = primitive->types[i];
        mat_multiply_matrix_vector_d3(conv_prim->position[i],
                                      trans_mat,
                                      primitive->position[i]);
        for (j = 0; j < 3; j++) {
            conv_prim->position[i][j] -= spacegroup->origin_shift[j];
            conv_prim->position[i][j] -= mat_Nint(conv_prim->position[i][j]);
        }
    }

    return conv_prim;
}
Example #7
0
static int get_operation_supercell( int rot[][3][3],
				    double trans[][3],
				    const int num_sym, 
				    const VecDBL * pure_trans,
				    SPGCONST Cell *cell,
				    SPGCONST Cell *primitive )
{
  int i, j, k, multi;
  double inv_prim_lat[3][3], drot[3][3], trans_mat[3][3], trans_mat_inv[3][3];
  MatINT *rot_prim;
  VecDBL *trans_prim;

  rot_prim = mat_alloc_MatINT( num_sym );
  trans_prim = mat_alloc_VecDBL( num_sym );
  multi = pure_trans->size;

  debug_print("get_operation_supercell\n");

  mat_inverse_matrix_d3( inv_prim_lat, primitive->lattice, 0 );
  mat_multiply_matrix_d3( trans_mat, inv_prim_lat, cell->lattice );
  mat_inverse_matrix_d3( trans_mat_inv, trans_mat, 0 );

  for( i = 0; i < num_sym; i++) {

    /* Translations  */
    mat_multiply_matrix_vector_d3( trans[i], trans_mat_inv, trans[i] );

    /* Rotations */
    mat_cast_matrix_3i_to_3d( drot, rot[i] );
    mat_get_similar_matrix_d3( drot, drot, trans_mat, 0 );
    mat_cast_matrix_3d_to_3i( rot[i], drot );
  }

  for( i = 0; i < num_sym; i++ ) {
    mat_copy_matrix_i3( rot_prim->mat[i], rot[i] );
    for( j = 0; j < 3; j++ )
      trans_prim->vec[i][j] = trans[i][j];
  }

  /* Rotations and translations are copied with the set of */
  /* pure translations. */
  for( i = 0; i < num_sym; i++ ) {
    for( j = 0; j < multi; j++ ) {
      mat_copy_matrix_i3( rot[ i * multi + j ], rot_prim->mat[i] );
      for ( k = 0; k < 3; k++ ) {
	trans[i * multi + j][k] =
	  mat_Dmod1( trans_prim->vec[i][k] + pure_trans->vec[j][k] );
      }
    }
  }

  mat_free_MatINT( rot_prim );
  mat_free_VecDBL( trans_prim );

  /* return number of symmetry operation of supercell */
  return num_sym * multi;
}
Example #8
0
static int is_overlap_all_atoms(const double trans[3],
				SPGCONST int rot[3][3],
				SPGCONST Cell * cell,
				const double symprec,
				const int is_identity)
{
  int i, j, k, is_found;
  double symprec2;
  double pos_rot[3], d[3];

  symprec2 = symprec*symprec;
  
  for (i = 0; i < cell->size; i++) {
    if (is_identity) { /* Identity matrix is treated as special for speed. */
      for (j = 0; j < 3; j++) {
	pos_rot[j] = cell->position[i][j] + trans[j];
      }
    } else {
      mat_multiply_matrix_vector_id3(pos_rot,
				     rot,
				     cell->position[i]);
      for (j = 0; j < 3; j++) {
	pos_rot[j] += trans[j];
      }
    }

    is_found = 0;
    for (j = 0; j < cell->size; j++) {
      if (cell->types[i] == cell->types[j]) {
	/* here cel_is_overlap can be used, but for the tuning */
	/* purpose, write it again */
	for (k = 0; k < 3; k++) {
	  d[k] = pos_rot[k] - cell->position[j][k];
	  d[k] -= mat_Nint(d[k]);
	}
	mat_multiply_matrix_vector_d3(d, cell->lattice, d);
	if (d[0]*d[0]+d[1]*d[1]+d[2]*d[2] < symprec2) {
	  is_found = 1;
	  break;
	}
      }
    }

    if (! is_found) {
      goto not_found;
    }
  }

  return 1;  /* found */

 not_found:
  return 0;
}
Example #9
0
static Symmetry * get_primitive_db_symmetry(SPGCONST double t_mat[3][3],
        const Symmetry *conv_sym,
        const double symprec)
{
    int i, j, num_op;
    double inv_mat[3][3], tmp_mat[3][3];
    MatINT *r_prim;
    VecDBL *t_prim;
    Symmetry *prim_sym;

    r_prim = mat_alloc_MatINT(conv_sym->size);
    t_prim = mat_alloc_VecDBL(conv_sym->size);

    mat_inverse_matrix_d3(inv_mat, t_mat, symprec);

    num_op = 0;
    for (i = 0; i < conv_sym->size; i++) {
        for (j = 0; j < i; j++) {
            if (mat_check_identity_matrix_i3(conv_sym->rot[i],
                                             conv_sym->rot[j])) {
                goto pass;
            }
        }

        /* R' = T*R*T^-1 */
        mat_multiply_matrix_di3(tmp_mat, t_mat, conv_sym->rot[i]);
        mat_multiply_matrix_d3(tmp_mat, tmp_mat, inv_mat);
        mat_cast_matrix_3d_to_3i(r_prim->mat[ num_op ], tmp_mat);
        /* t' = T*t */
        mat_multiply_matrix_vector_d3(t_prim->vec[ num_op ],
                                      t_mat,
                                      conv_sym->trans[ i ]);
        num_op++;

pass:
        ;
    }

    prim_sym = sym_alloc_symmetry(num_op);
    for (i = 0; i < num_op; i++) {
        mat_copy_matrix_i3(prim_sym->rot[i], r_prim->mat[i]);
        for (j = 0; j < 3; j++) {
            prim_sym->trans[i][j] = t_prim->vec[i][j] - mat_Nint(t_prim->vec[i][j]);
        }
    }

    mat_free_MatINT(r_prim);
    mat_free_VecDBL(t_prim);

    return prim_sym;
}
Example #10
0
static Symmetry * recover_operations_original(SPGCONST Symmetry *symmetry,
					      const VecDBL * pure_trans,
					      SPGCONST Cell *cell,
					      SPGCONST Cell *primitive)
{
  int i, j, k, multi;
  double inv_prim_lat[3][3], drot[3][3], trans_mat[3][3], trans_mat_inv[3][3];
  Symmetry *symmetry_orig, *sym_tmp;

  debug_print("recover_operations_original:\n");

  multi = pure_trans->size;
  sym_tmp = sym_alloc_symmetry(symmetry->size);
  symmetry_orig = sym_alloc_symmetry(symmetry->size * multi);

  mat_inverse_matrix_d3(inv_prim_lat, primitive->lattice, 0);
  mat_multiply_matrix_d3(trans_mat, inv_prim_lat, cell->lattice);
  mat_inverse_matrix_d3(trans_mat_inv, trans_mat, 0);

  for(i = 0; i < symmetry->size; i++) {
    mat_copy_matrix_i3(sym_tmp->rot[i], symmetry->rot[i]);
    mat_copy_vector_d3(sym_tmp->trans[i], symmetry->trans[i]);
  }

  for(i = 0; i < symmetry->size; i++) {
    mat_cast_matrix_3i_to_3d(drot, sym_tmp->rot[i]);
    mat_get_similar_matrix_d3(drot, drot, trans_mat, 0);
    mat_cast_matrix_3d_to_3i(sym_tmp->rot[i], drot);

    mat_multiply_matrix_vector_d3(sym_tmp->trans[i],
				  trans_mat_inv,
				  sym_tmp->trans[i]);
  }


  for(i = 0; i < symmetry->size; i++) {
    for(j = 0; j < multi; j++) {
      mat_copy_matrix_i3(symmetry_orig->rot[i * multi + j], sym_tmp->rot[i]);
      for (k = 0; k < 3; k++) {
	symmetry_orig->trans[i * multi + j][k] =
	  sym_tmp->trans[i][k] + pure_trans->vec[j][k];
      }
    }
  }

  sym_free_symmetry(sym_tmp);

  return symmetry_orig;
}
Example #11
0
int cel_is_overlap( const double a[3],
		    const double b[3],
		    SPGCONST double lattice[3][3],
		    const double symprec )
{
  int i;
  double v_diff[3];

  for ( i = 0; i < 3; i++ ) {
    v_diff[i] = a[i] - b[i];
    v_diff[i] -= mat_Nint( v_diff[i] );
  }

  mat_multiply_matrix_vector_d3( v_diff, lattice, v_diff );
  if ( mat_norm_squared_d3( v_diff ) < symprec*symprec ) {
    return 1;
  } else {
    return 0;
  }
}
Example #12
0
/* Return NULL if failed */
static Cell * get_cell_with_smallest_lattice(SPGCONST Cell * cell,
					     const double symprec)
{
  int i, j;
  double min_lat[3][3], trans_mat[3][3], inv_lat[3][3];
  Cell * smallest_cell;

  debug_print("get_cell_with_smallest_lattice:\n");
  
  smallest_cell = NULL;

  if (!lat_smallest_lattice_vector(min_lat,
				   cell->lattice,
				   symprec)) {
    goto err;
  }

  mat_inverse_matrix_d3(inv_lat, min_lat, 0);
  mat_multiply_matrix_d3(trans_mat, inv_lat, cell->lattice);

  if ((smallest_cell = cel_alloc_cell(cell->size)) == NULL) {
    goto err;
  }

  mat_copy_matrix_d3(smallest_cell->lattice, min_lat);
  for (i = 0; i < cell->size; i++) {
    smallest_cell->types[i] = cell->types[i];
    mat_multiply_matrix_vector_d3(smallest_cell->position[i],
				  trans_mat, cell->position[i]);
    for (j = 0; j < 3; j++) {
      cell->position[i][j] = mat_Dmod1(cell->position[i][j]);
    }
  }

  return smallest_cell;

 err:
  return NULL;
}
Example #13
0
/* Return NULL if failed */
static VecDBL * get_lattice_translations(const int frame[3],
					 SPGCONST double inv_tmat[3][3])
{
  int i, j, k, l, num_trans;
  VecDBL * lattice_trans;

  lattice_trans = NULL;

  if ((lattice_trans = mat_alloc_VecDBL(frame[0] * frame[1] * frame[2]))
      == NULL) {
    return NULL;
  }

  num_trans = 0;
  for (i = 0; i < frame[0]; i++) {
    for (j = 0; j < frame[1]; j++) {
      for (k = 0; k < frame[2]; k++) {
	lattice_trans->vec[num_trans][0] = i;
	lattice_trans->vec[num_trans][1] = j;
	lattice_trans->vec[num_trans][2] = k;

	/* t' = T^-1*t */
	mat_multiply_matrix_vector_d3(lattice_trans->vec[num_trans],
				      inv_tmat,
				      lattice_trans->vec[num_trans]);
	for (l = 0; l < 3; l++) {
	  lattice_trans->vec[num_trans][l] =
	    mat_Dmod1(lattice_trans->vec[num_trans][l]);
	}
	num_trans++;
      }
    }
  }

  return lattice_trans;
}
Example #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[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;
}
Example #15
0
/* Acta Cryst. (2002). A58, 60-65 */
static int set_exact_location(double position[3],
                              const Symmetry * conv_sym,
                              SPGCONST double bravais_lattice[3][3],
                              const double symprec)
{
  int i, j, k, num_sum, multi, num_pure_trans;
  double sum_rot[3][3];
  double pos[3], sum_trans[3];

  debug_print("get_exact_location\n");

  num_sum = 0;
  for (i = 0; i < 3; i++) {
    sum_trans[i] = 0.0;
    for (j = 0; j < 3; j++) {
      sum_rot[i][j] = 0;
    }
  }

  num_pure_trans = 0;
  for (i = 0; i < conv_sym->size; i++) {
    if (mat_check_identity_matrix_i3(identity, conv_sym->rot[i])) {
      num_pure_trans++;
      for (j = 0; j < 3; j++) {
        pos[j] = position[j];
      }
    } else {
      mat_multiply_matrix_vector_id3(pos,
                                     conv_sym->rot[i],
                                     position);
    }
    for (j = 0; j < 3; j++) {
      pos[j] += conv_sym->trans[i][j];
    }

    if (cel_is_overlap(pos,
                       position,
                       bravais_lattice,
                       symprec)) {
      for (j = 0; j < 3; j++) {
        for (k = 0; k < 3; k++) {
          sum_rot[j][k] += conv_sym->rot[i][j][k];
        }
        sum_trans[j] +=
          conv_sym->trans[i][j] - mat_Nint(pos[j] - position[j]);
      }
      num_sum++;
    }
  }

  for (i = 0; i < 3; i++) {
    sum_trans[i] /= num_sum;
    for (j = 0; j < 3; j++) {
      sum_rot[i][j] /= num_sum;
    }
  }

  /* (sum_rot|sum_trans) is the special-position operator. */
  /* Elements of sum_rot can be fractional values. */
  mat_multiply_matrix_vector_d3(position,
                                sum_rot,
                                position);

  for (i = 0; i < 3; i++) {
    position[i] += sum_trans[i];
  }

  multi = conv_sym->size / num_pure_trans / num_sum;
  if (multi * num_sum * num_pure_trans == conv_sym->size) {
    return multi;
  } else {
    return 0;
  }
}
Example #16
0
static Symmetry * get_conventional_symmetry(SPGCONST double transform_mat[3][3],
        const Centering centering,
        const Symmetry *primitive_sym)
{
    int i, j, k, multi, size;
    double tmp_trans;
    double tmp_matrix_d3[3][3], shift[4][3];
    double symmetry_rot_d3[3][3], primitive_sym_rot_d3[3][3];
    Symmetry *symmetry;

    size = primitive_sym->size;

    if (centering == FACE) {
        symmetry = sym_alloc_symmetry(size * 4);
    }
    else {
        if (centering) {
            symmetry = sym_alloc_symmetry(size * 2);
        } else {
            symmetry = sym_alloc_symmetry(size);
        }
    }

    for (i = 0; i < size; i++) {
        mat_cast_matrix_3i_to_3d(primitive_sym_rot_d3, primitive_sym->rot[i]);

        /* C*S*C^-1: recover conventional cell symmetry operation */
        mat_get_similar_matrix_d3(symmetry_rot_d3,
                                  primitive_sym_rot_d3,
                                  transform_mat,
                                  0);
        mat_cast_matrix_3d_to_3i(symmetry->rot[i], symmetry_rot_d3);

        /* translation in conventional cell: C = B^-1*P */
        mat_inverse_matrix_d3(tmp_matrix_d3,
                              transform_mat,
                              0);
        mat_multiply_matrix_vector_d3(symmetry->trans[i],
                                      tmp_matrix_d3,
                                      primitive_sym->trans[i]);
    }

    multi = 1;

    if (centering) {
        if (! (centering == FACE)) {
            for (i = 0; i < 3; i++) {
                shift[0][i] = 0.5;
            }
            if (centering == A_FACE) {
                shift[0][0] = 0;
            }
            if (centering == B_FACE) {
                shift[0][1] = 0;
            }
            if (centering == C_FACE) {
                shift[0][2] = 0;
            }

            multi = 2;
        }

        if (centering == FACE) {
            shift[0][0] = 0;
            shift[0][1] = 0.5;
            shift[0][2] = 0.5;
            shift[1][0] = 0.5;
            shift[1][1] = 0;
            shift[1][2] = 0.5;
            shift[2][0] = 0.5;
            shift[2][1] = 0.5;
            shift[2][2] = 0;

            multi = 4;
        }

        for (i = 0; i < multi - 1; i++) {
            for (j = 0; j < size; j++) {
                mat_copy_matrix_i3(symmetry->rot[(i+1) * size + j],
                                   symmetry->rot[j]);
                for (k = 0; k < 3; k++) {
                    tmp_trans = symmetry->trans[j][k] + shift[i][k];
                    symmetry->trans[(i+1) * size + j][k] = tmp_trans;
                }
            }
        }
    }


    /* Reduce translations into -0 < trans < 1.0 */
    for (i = 0; i < multi; i++) {
        for (j = 0; j < size; j++) {
            for (k = 0; k < 3; k++) {
                tmp_trans = symmetry->trans[i * size + j][k];
                tmp_trans -= mat_Nint(tmp_trans);
                if (tmp_trans < 0) {
                    tmp_trans += 1.0;
                }
                symmetry->trans[i * size + j][k] = tmp_trans;
            }
        }
    }

    return symmetry;
}
Example #17
0
/* 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];

  /* Multithreading doesn't work for this loop since gp calculated */
  /* with boundary_num_gp is unstable to store bz_grid_address. */
  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] + 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] + bz_search_space[j][k] * mesh[k];
	  bz_address_double[k] = bz_grid_address[gp][k] * 2 + is_shift[k];
	}
	bzgp = kgd_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;
}
Example #18
0
static Symmetry * reduce_symmetry_in_frame(const int frame[3],
        SPGCONST Symmetry *prim_sym,
        SPGCONST int t_mat[3][3],
        SPGCONST double lattice[3][3],
        const int multiplicity,
        const double symprec)
{
    int i, j, k, l, num_trans, size_sym_orig;
    Symmetry *symmetry, *t_sym;
    double inv_tmat[3][3], tmp_mat[3][3], tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3];
    int tmp_rot_i[3][3];
    VecDBL *pure_trans, *lattice_trans;

    mat_cast_matrix_3i_to_3d(tmp_mat, t_mat);
    mat_inverse_matrix_d3(inv_tmat, tmp_mat, symprec);

    /* transformed lattice points */
    lattice_trans = mat_alloc_VecDBL(frame[0]*frame[1]*frame[2]);
    num_trans = 0;
    for (i = 0; i < frame[0]; i++) {
        for (j = 0; j < frame[1]; j++) {
            for (k = 0; k < frame[2]; k++) {
                lattice_trans->vec[num_trans][0] = i;
                lattice_trans->vec[num_trans][1] = j;
                lattice_trans->vec[num_trans][2] = k;

                mat_multiply_matrix_vector_d3(lattice_trans->vec[num_trans],
                                              inv_tmat,
                                              lattice_trans->vec[num_trans]);
                for (l = 0; l < 3; l++) {
                    /* t' = T^-1*t */
                    lattice_trans->vec[num_trans][l] = \
                                                       mat_Dmod1(lattice_trans->vec[num_trans][l]);
                }
                num_trans++;
            }
        }
    }

    /* transformed symmetry operations of primitive cell */
    t_sym = sym_alloc_symmetry(prim_sym->size);
    size_sym_orig = 0;
    for (i = 0; i < prim_sym->size; i++) {
        /* R' = T^-1*R*T */
        mat_multiply_matrix_di3(tmp_mat, inv_tmat, prim_sym->rot[i]);
        mat_multiply_matrix_di3(tmp_rot_d, tmp_mat, t_mat);
        mat_cast_matrix_3d_to_3i(tmp_rot_i, tmp_rot_d);
        mat_multiply_matrix_di3(tmp_lat_i, lattice, tmp_rot_i);
        mat_multiply_matrix_d3(tmp_lat_d, lattice, tmp_rot_d);
        if (mat_check_identity_matrix_d3(tmp_lat_i, tmp_lat_d, symprec)) {
            mat_copy_matrix_i3(t_sym->rot[size_sym_orig], tmp_rot_i);
            /* t' = T^-1*t */
            mat_multiply_matrix_vector_d3(t_sym->trans[size_sym_orig],
                                          inv_tmat, prim_sym->trans[i]);
            size_sym_orig++;
        }
    }

    /* reduce lattice points */
    pure_trans = reduce_lattice_points(lattice,
                                       lattice_trans,
                                       symprec);

    if (! (pure_trans->size == multiplicity)) {
        symmetry = sym_alloc_symmetry(0);
        goto ret;
    }

    /* copy symmetry operations upon lattice points */
    symmetry = sym_alloc_symmetry(pure_trans->size * size_sym_orig);
    for (i = 0; i < pure_trans->size; i++) {
        for (j = 0; j < size_sym_orig; j++) {
            mat_copy_matrix_i3(symmetry->rot[size_sym_orig * i + j],
                               t_sym->rot[j]);
            mat_copy_vector_d3(symmetry->trans[size_sym_orig * i + j],
                               t_sym->trans[j]);
            for (k = 0; k < 3; k++) {
                symmetry->trans[size_sym_orig * i + j][k] += pure_trans->vec[i][k];
                symmetry->trans[size_sym_orig * i + j][k] = \
                        mat_Dmod1(symmetry->trans[size_sym_orig * i + j][k]);
            }
        }
    }


ret:
    mat_free_VecDBL(lattice_trans);
    mat_free_VecDBL(pure_trans);
    sym_free_symmetry(t_sym);

    return symmetry;
}
Example #19
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;
}
Example #20
0
/* Return NULL if failed */
static Symmetry *
get_symmetry_in_original_cell(SPGCONST int t_mat[3][3],
			      SPGCONST double inv_tmat[3][3],
			      SPGCONST double lattice[3][3],
			      SPGCONST Symmetry *prim_sym,
			      const double symprec)
{
  int i, size_sym_orig;
  double tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3], tmp_mat[3][3];
  int tmp_rot_i[3][3];
  Symmetry *t_sym, *t_red_sym;

  t_sym = NULL;
  t_red_sym = NULL;

  if ((t_sym = sym_alloc_symmetry(prim_sym->size)) == NULL) {
    return NULL;
  }

  /* transform symmetry operations of primitive cell to those of original */
  size_sym_orig = 0;
  for (i = 0; i < prim_sym->size; i++) {
    /* R' = T^-1*R*T */
    mat_multiply_matrix_di3(tmp_mat, inv_tmat, prim_sym->rot[i]);
    mat_multiply_matrix_di3(tmp_rot_d, tmp_mat, t_mat);

    /* In spglib, symmetry of supercell is defined by the set of symmetry */
    /* operations that are searched among supercell lattice point group */
    /* operations. The supercell lattice may be made by breaking the */
    /* unit cell lattice symmetry. In this case, a part of symmetry */
    /* operations is discarded. */
    mat_cast_matrix_3d_to_3i(tmp_rot_i, tmp_rot_d);
    mat_multiply_matrix_di3(tmp_lat_i, lattice, tmp_rot_i);
    mat_multiply_matrix_d3(tmp_lat_d, lattice, tmp_rot_d);
    if (mat_check_identity_matrix_d3(tmp_lat_i, tmp_lat_d, symprec)) {
      mat_copy_matrix_i3(t_sym->rot[size_sym_orig], tmp_rot_i);
      /* t' = T^-1*t */
      mat_multiply_matrix_vector_d3(t_sym->trans[size_sym_orig],
				    inv_tmat,
				    prim_sym->trans[i]);
      size_sym_orig++;
    }
  }

  /* Broken symmetry due to supercell multiplicity */
  if (size_sym_orig != prim_sym->size) {

    if ((t_red_sym = sym_alloc_symmetry(size_sym_orig)) == NULL) {
      sym_free_symmetry(t_sym);
      t_sym = NULL;
      return NULL;
    }

    for (i = 0; i < size_sym_orig; i++) {
      mat_copy_matrix_i3(t_red_sym->rot[i], t_sym->rot[i]);
      mat_copy_vector_d3(t_red_sym->trans[i], t_sym->trans[i]);
    }

    sym_free_symmetry(t_sym);
    t_sym = NULL;

    t_sym = t_red_sym;
    t_red_sym = NULL;
  }

  return t_sym;
}
Example #21
0
static Symmetry * reduce_symmetry_in_frame( const int frame[3],
					    SPGCONST Symmetry *prim_sym,
					    SPGCONST int t_mat[3][3],
					    SPGCONST double lattice[3][3],
					    const double symprec )
{
  int i, j, k, l, n, num_op, is_found;
  Symmetry *symmetry, *t_sym;
  double inv_mat[3][3], tmp_mat[3][3];
  VecDBL *t, *lattice_trans;

  mat_cast_matrix_3i_to_3d( tmp_mat, t_mat );
  mat_inverse_matrix_d3( inv_mat, tmp_mat, symprec );

  /* transformed lattice points */
  lattice_trans = mat_alloc_VecDBL( frame[0]*frame[1]*frame[2] );
  n = 0;
  for ( i = 0; i < frame[0]; i++ ) {
    for ( j = 0; j < frame[1]; j++ ) {
      for ( k = 0; k < frame[2]; k++ ) {
	lattice_trans->vec[n][0] = i;
	lattice_trans->vec[n][1] = j;
	lattice_trans->vec[n][2] = k;

	mat_multiply_matrix_vector_d3( lattice_trans->vec[n],
				       inv_mat,
				       lattice_trans->vec[n] );
	for ( l = 0; l < 3; l++ ) {
	  /* t' = T^-1*t */
	  lattice_trans->vec[n][l] = mat_Dmod1( lattice_trans->vec[n][l] ); 
	}
	n++;
      }
    }
  }

  /* transformed symmetry operations of primitive cell */
  t_sym = sym_alloc_symmetry( prim_sym->size );
  for ( i = 0; i < prim_sym->size; i++ ) {
    /* R' = T^-1*R*T */
    mat_multiply_matrix_di3( tmp_mat, inv_mat, prim_sym->rot[i] );
    mat_multiply_matrix_di3( tmp_mat, tmp_mat, t_mat );
    mat_cast_matrix_3d_to_3i( t_sym->rot[i], tmp_mat );
    /* t' = T^-1*t */
    mat_multiply_matrix_vector_d3( t_sym->trans[i], inv_mat, prim_sym->trans[ i ] );
  }

  /* reduce lattice points */
  num_op = 0;
  t = mat_alloc_VecDBL( lattice_trans->size );
  for ( i = 0; i < lattice_trans->size; i++ ) {
    is_found = 0;
    for ( j = 0; j < num_op; j++ ) {
      if ( cel_is_overlap( lattice_trans->vec[i], t->vec[j], lattice, symprec ) ) {
	is_found = 1;
	break;
      }
    }
    if ( ! is_found ) {
      mat_copy_vector_d3( t->vec[num_op], lattice_trans->vec[i] );
      num_op++;
    }
  }

  /* copy symmetry operations upon lattice points */
  symmetry = sym_alloc_symmetry( num_op * t_sym->size );
  for ( i = 0; i < num_op; i++ ) {
    for ( j = 0; j < t_sym->size; j++ ) {
      mat_copy_matrix_i3( symmetry->rot[ t_sym->size * i + j ], t_sym->rot[j] );
      mat_copy_vector_d3( symmetry->trans[ t_sym->size * i + j ], t_sym->trans[j] );
      for ( k = 0; k < 3; k++ ) {
	symmetry->trans[ t_sym->size * i + j ][k] += t->vec[i][k];
	symmetry->trans[ t_sym->size * i + j ][k] = \
	  mat_Dmod1( symmetry->trans[ t_sym->size * i + j ][k] );
      }
    }
  }
  
  mat_free_VecDBL( t );
  sym_free_symmetry( t_sym );

  return symmetry;
}
Example #22
0
/* Return 0 if failed */
static int get_primitive_lattice_vectors(double prim_lattice[3][3],
					 const VecDBL * vectors,
					 SPGCONST Cell * cell,
					 const double symprec)
{
  int i, j, k, size;
  double initial_volume, volume;
  double relative_lattice[3][3], min_vectors[3][3], tmp_lattice[3][3];
  double inv_mat_dbl[3][3];
  int inv_mat_int[3][3];

  debug_print("get_primitive_lattice_vectors:\n");

  size = vectors->size;
  initial_volume = mat_Dabs(mat_get_determinant_d3(cell->lattice));

  /* check volumes of all possible lattices, find smallest volume */
  for (i = 0; i < size; i++) {
    for (j = i + 1; j < size; j++) {
      for (k = j + 1; k < size; k++) {
	mat_multiply_matrix_vector_d3(tmp_lattice[0],
				      cell->lattice,
				      vectors->vec[i]);
	mat_multiply_matrix_vector_d3(tmp_lattice[1],
				      cell->lattice,
				      vectors->vec[j]);
	mat_multiply_matrix_vector_d3(tmp_lattice[2],
				      cell->lattice,
				      vectors->vec[k]);
	volume = mat_Dabs(mat_get_determinant_d3(tmp_lattice));
	if (volume > symprec) {
	  if (mat_Nint(initial_volume / volume) == size-2) {
	    mat_copy_vector_d3(min_vectors[0], vectors->vec[i]);
	    mat_copy_vector_d3(min_vectors[1], vectors->vec[j]);
	    mat_copy_vector_d3(min_vectors[2], vectors->vec[k]);
	    goto ret;
	  }
	}
      }
    }
  }

  /* Not found */
  warning_print("spglib: Primitive lattice vectors cound not be found ");
  warning_print("(line %d, %s).\n", __LINE__, __FILE__);
  return 0;

  /* Found */
 ret:
  for (i = 0; i < 3; i++) {
    for (j = 0; j < 3; j++) {
      relative_lattice[j][i] = min_vectors[i][j];
    }
  }

  mat_inverse_matrix_d3(inv_mat_dbl, relative_lattice, 0);
  mat_cast_matrix_3d_to_3i(inv_mat_int, inv_mat_dbl);
  if (abs(mat_get_determinant_i3(inv_mat_int)) == size-2) {
    mat_cast_matrix_3i_to_3d(inv_mat_dbl, inv_mat_int);
    mat_inverse_matrix_d3(relative_lattice, inv_mat_dbl, 0);
  } else {
    warning_print("spglib: Primitive lattice cleaning is incomplete ");
    warning_print("(line %d, %s).\n", __LINE__, __FILE__);
  }
  mat_multiply_matrix_d3(prim_lattice, cell->lattice, relative_lattice);

  return 1;  
}
Example #23
0
/* Return NULL if failed */
static Symmetry * get_conventional_symmetry(SPGCONST double transform_mat[3][3],
					    const Centering centering,
					    const Symmetry *primitive_sym)
{
  int i, j, k, multi, size;
  double inv_tmat[3][3], shift[4][3];
  double symmetry_rot_d3[3][3], primitive_sym_rot_d3[3][3];
  Symmetry *symmetry;

  symmetry = NULL;

  size = primitive_sym->size;

  switch (centering) {
  case FACE:
    if ((symmetry = sym_alloc_symmetry(size * 4)) == NULL) {
      return NULL;
    }
    break;
  case R_CENTER:
    if ((symmetry = sym_alloc_symmetry(size * 3)) == NULL) {
      return NULL;
    }
    break;
  case BODY:
  case A_FACE:
  case B_FACE:
  case C_FACE:
    if ((symmetry = sym_alloc_symmetry(size * 2)) == NULL) {
      return NULL;
    }
    break;
  default:
    if ((symmetry = sym_alloc_symmetry(size)) == NULL) {
      return NULL;
    }
    break;
  }

  for (i = 0; i < size; i++) {
    mat_cast_matrix_3i_to_3d(primitive_sym_rot_d3, primitive_sym->rot[i]);

    /* C*S*C^-1: recover conventional cell symmetry operation */
    mat_get_similar_matrix_d3(symmetry_rot_d3,
			      primitive_sym_rot_d3,
			      transform_mat,
			      0);
    mat_cast_matrix_3d_to_3i(symmetry->rot[i], symmetry_rot_d3);

    /* translation in conventional cell: C = B^-1*P */
    mat_inverse_matrix_d3(inv_tmat, transform_mat, 0);
    mat_multiply_matrix_vector_d3(symmetry->trans[i],
				  inv_tmat,
				  primitive_sym->trans[i]);
  }

  multi = 1;

  if (centering != PRIMITIVE) {
    if (centering != FACE && centering != R_CENTER) {
      for (i = 0; i < 3; i++) {	shift[0][i] = 0.5; } /* BASE */
      if (centering == A_FACE) { shift[0][0] = 0; }
      if (centering == B_FACE) { shift[0][1] = 0; }
      if (centering == C_FACE) { shift[0][2] = 0; }
      multi = 2;
    }

    if (centering == R_CENTER) {
      shift[0][0] = 2. / 3;
      shift[0][1] = 1. / 3;
      shift[0][2] = 1. / 3;
      shift[1][0] = 1. / 3;
      shift[1][1] = 2. / 3;
      shift[1][2] = 2. / 3;
      multi = 3;
    }

    if (centering == FACE) {
      shift[0][0] = 0;
      shift[0][1] = 0.5;
      shift[0][2] = 0.5;
      shift[1][0] = 0.5;
      shift[1][1] = 0;
      shift[1][2] = 0.5;
      shift[2][0] = 0.5;
      shift[2][1] = 0.5;
      shift[2][2] = 0;
      multi = 4;
    }

    for (i = 0; i < multi - 1; i++) {
      for (j = 0; j < size; j++) {
	mat_copy_matrix_i3(symmetry->rot[(i+1) * size + j],
			   symmetry->rot[j]);
	for (k = 0; k < 3; k++) {
	  symmetry->trans[(i+1) * size + j][k] =
	    symmetry->trans[j][k] + shift[i][k];
	}
      }
    }
  }

  for (i = 0; i < multi; i++) {
    for (j = 0; j < size; j++) {
      for (k = 0; k < 3; k++) {
  	symmetry->trans[i * size + j][k] =
	  mat_Dmod1(symmetry->trans[i * size + j][k]);
      }
    }
  }

  return symmetry;
}