int cube(double particle_origin[],std::vector<cs::catom_t> & catom_array, const int grain){ //---------------------------------------------------------- // check calling of routine if error checking is activated //---------------------------------------------------------- if(err::check==true){std::cout << "cs::cube has been called" << std::endl;} // Set particle size double side_length=cs::particle_scale*0.5; // Loop over all atoms and mark atoms in cube const int num_atoms = catom_array.size(); // determine order for core-shell particles std::list<core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(compare_radius); for(int atom=0;atom<num_atoms;atom++){ double dx=fabs(catom_array[atom].x-particle_origin[0]); double dy=fabs(catom_array[atom].y-particle_origin[1]); if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; double my_length = mp::material[mat].core_shell_size; double max_length = my_length*side_length; double maxz=mp::material[mat].max*cs::system_dimensions[2]; double minz=mp::material[mat].min*cs::system_dimensions[2]; double cz=catom_array[atom].z; // check for within core shell range if((dx<=max_length) && (dy<=max_length)){ if((cz>=minz) && (cz<maxz)){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } else if((dx<=side_length) && (dy<=side_length)){ catom_array[atom].include=true; catom_array[atom].grain=grain; } } return EXIT_SUCCESS; }
int truncated_octahedron(double particle_origin[],std::vector<cs::catom_t> & catom_array, const int grain){ //==================================================================================== // /// cs_truncated_octahedron /// /// Subroutine to cut a truncated octahedron particle shape /// /// Version 1.0 R Evans 22/09/2008 /// //==================================================================================== // check calling of routine if error checking is activated if(err::check==true){std::cout << "cs::truncated_octahedron has been called" << std::endl;} // Set truncated octahedron parameters const double sfx = cs::particle_shape_factor_x; const double sfy = cs::particle_shape_factor_y; const double sfz = cs::particle_shape_factor_z; const double to_length = cs::particle_scale*0.5*3.0/2.0; const double to_height = cs::particle_scale*0.5; //const double to_length = cs::particle_scale*0.5; //const double to_height = to_length*2.0/3.0; double x_vector[3]; // Loop over all atoms and mark atoms in truncate octahedron const int num_atoms = catom_array.size(); // determine order for core-shell particles std::list<core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(compare_radius); for(int atom=0;atom<num_atoms;atom++){ x_vector[0] = fabs(catom_array[atom].x-particle_origin[0]); x_vector[1] = fabs(catom_array[atom].y-particle_origin[1]); x_vector[2] = fabs(catom_array[atom].z-particle_origin[2]); double range = x_vector[0] + x_vector[1] + x_vector[2]; if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; double my_radius = mp::material[mat].core_shell_size; double my_to_height = my_radius*to_height; double my_to_length = my_radius*to_length; double maxz=mp::material[mat].max*cs::system_dimensions[2]; double minz=mp::material[mat].min*cs::system_dimensions[2]; double cz=catom_array[atom].z; // check for within core shell range if((range<=my_to_length) && (x_vector[0] <= my_to_height*sfx) && (x_vector[1] <= my_to_height*sfy) && (x_vector[2] <= my_to_height*sfz)){ if((cz>=minz) && (cz<maxz)){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } else if((range<=to_length) && (x_vector[0] <= to_height*sfx) && (x_vector[1] <= to_height*sfy) && (x_vector[2] <= to_height*sfz)){ catom_array[atom].include=true; catom_array[atom].grain=grain; } } return EXIT_SUCCESS; }
int sphere(double particle_origin[],std::vector<cs::catom_t> & catom_array, const int grain){ //==================================================================================== /// /// cs_sphere /// /// Subroutine to cut a spherical particle shape /// /// Version 1.0 R Evans 22/09/2008 // //==================================================================================== //---------------------------------------------------------- // check calling of routine if error checking is activated //---------------------------------------------------------- if(err::check==true){std::cout << "cs::sphere has been called" << std::endl;} // Set particle radius double particle_radius_squared = (cs::particle_scale*0.5)*(cs::particle_scale*0.5); // Loop over all atoms and mark atoms in sphere const int num_atoms = catom_array.size(); // determine order for core-shell particles std::list<core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(compare_radius); for(int atom=0;atom<num_atoms;atom++){ double range_squared = (catom_array[atom].x-particle_origin[0])*(catom_array[atom].x-particle_origin[0]) + (catom_array[atom].y-particle_origin[1])*(catom_array[atom].y-particle_origin[1]) + (catom_array[atom].z-particle_origin[2])*(catom_array[atom].z-particle_origin[2]); if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; double my_radius = mp::material[mat].core_shell_size; double max_range = my_radius*my_radius*particle_radius_squared; double maxz=mp::material[mat].max*cs::system_dimensions[2]; double minz=mp::material[mat].min*cs::system_dimensions[2]; double cz=catom_array[atom].z; // check for within core shell range if(range_squared<=max_range){ if((cz>=minz) && (cz<maxz)){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } else if(range_squared<=particle_radius_squared) { catom_array[atom].include=true; catom_array[atom].grain=grain; } } return EXIT_SUCCESS; }
void ellipsoid(double particle_origin[],std::vector<cs::catom_t> & catom_array, const int grain){ //-------------------------------------------------------------------------------------------- // /// Function to cut an ellipsoid particle shape /// /// (C) R F L Evans 23/04/2013 /// /// Equation for an ellipsoid is: /// /// (x-h)^2 (y-k)^2 (z-l)^2 /// ------- ------- ------- <= 1 /// r_x^2 r_y^2 r_z^2 /// /// Evaluation of the above for particle coordinates h,k,l /// and atomic positions x,y,z will include all atoms within /// ellipse with vertices r_x, r_y and r_z. // //-------------------------------------------------------------------------------------------- // check calling of routine if error checking is activated if(err::check==true){std::cout << "cs::ellipsoid has been called" << std::endl;} // Set particle radius const double particle_radius_squared = (cs::particle_scale*0.5)*(cs::particle_scale*0.5); // Use shape modifiers to generate ellipsoid const double inv_rx_sq = 1.0/(particle_radius_squared*cs::particle_shape_factor_x*cs::particle_shape_factor_x); const double inv_ry_sq = 1.0/(particle_radius_squared*cs::particle_shape_factor_y*cs::particle_shape_factor_y); const double inv_rz_sq = 1.0/(particle_radius_squared*cs::particle_shape_factor_z*cs::particle_shape_factor_z); // Loop over all atoms and mark atoms in sphere const int num_atoms = catom_array.size(); // determine order for core-shell particles std::list<core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(compare_radius); for(int atom=0;atom<num_atoms;atom++){ const double range_x_sq = (catom_array[atom].x-particle_origin[0])*(catom_array[atom].x-particle_origin[0]); const double range_y_sq = (catom_array[atom].y-particle_origin[1])*(catom_array[atom].y-particle_origin[1]); const double range_z_sq = (catom_array[atom].z-particle_origin[2])*(catom_array[atom].z-particle_origin[2]); if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; const double my_radius_sq = mp::material[mat].core_shell_size*mp::material[mat].core_shell_size; double maxz=mp::material[mat].max*cs::system_dimensions[2]; double minz=mp::material[mat].min*cs::system_dimensions[2]; double cz=catom_array[atom].z; // check for within core shell range if(range_x_sq*inv_rx_sq + range_y_sq*inv_ry_sq +range_z_sq*inv_rz_sq<=my_radius_sq){ if((cz>=minz) && (cz<maxz)){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } else if(range_x_sq*inv_rx_sq + range_y_sq*inv_ry_sq +range_z_sq*inv_rz_sq<=1.0) { catom_array[atom].include=true; catom_array[atom].grain=grain; } } return; }
void sphere(std::vector<double>& particle_origin, std::vector<cs::catom_t> & catom_array, const int grain){ // Set particle radius double particle_radius_squared = (cs::particle_scale*0.5)*(cs::particle_scale*0.5); // Loop over all atoms and mark atoms in sphere const int num_atoms = catom_array.size(); // determine order for core-shell particles std::list<core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(compare_radius); // Unroll min, max and fill for performance std::vector<double> mat_min(mp::num_materials); std::vector<double> mat_max(mp::num_materials); std::vector<double> mat_cssize(mp::num_materials); std::vector<int> uc_cat(mp::num_materials); // array of material -> unit cell material associations for(int mat=0;mat<mp::num_materials;mat++){ mat_min[mat]=create::internal::mp[mat].min*cs::system_dimensions[2]; mat_max[mat]=create::internal::mp[mat].max*cs::system_dimensions[2]; mat_cssize[mat] = mp::material[mat].core_shell_size; // alloys generally are not defined by height, and so have max = 0.0 if(mat_max[mat]<1.e-99) mat_max[mat]=-0.1; uc_cat[mat] = create::internal::mp[mat].unit_cell_category; // unit cell category of material } for(int atom=0;atom<num_atoms;atom++){ double range_squared = (catom_array[atom].x-particle_origin[0])*(catom_array[atom].x-particle_origin[0]) + (catom_array[atom].y-particle_origin[1])*(catom_array[atom].y-particle_origin[1]) + (catom_array[atom].z-particle_origin[2])*(catom_array[atom].z-particle_origin[2]); const double cz=catom_array[atom].z; const int atom_uc_cat = catom_array[atom].uc_category; if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; double my_radius = mat_cssize[mat]; double max_range = my_radius*my_radius*particle_radius_squared; double maxz=mat_max[mat]; double minz=mat_min[mat]; // check for within core shell range if(range_squared<=max_range){ if((cz>=minz) && (cz<maxz) && (atom_uc_cat == uc_cat[mat]) ){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } else if(range_squared<=particle_radius_squared) { catom_array[atom].include=true; catom_array[atom].grain=grain; } } return; }
int voronoi_film(std::vector<cs::catom_t> & catom_array){ // check calling of routine if error checking is activated if(err::check==true){ terminaltextcolor(RED); std::cerr << "cs::voronoi_film has been called" << std::endl; terminaltextcolor(WHITE); } //==================================================================================== // // voronoi // // Subroutine to create granular system using qhull voronoi generator // // Version 1.0 R Evans 16/07/2009 // //==================================================================================== // // Locally allocated variables: init_grain_coord_array // init_grain_pointx_array // init_grain_pointy_array // init_num_assoc_vertices_array // //===================================================================================== //--------------------------------------------------- // Local constants //--------------------------------------------------- const int max_vertices=50; double grain_sd=create_voronoi::voronoi_sd; // Set number of particles in x and y directions double size = create::internal::voronoi_grain_size + create::internal::voronoi_grain_spacing; double grain_cell_size_x = size; double grain_cell_size_y = sqrt(3.0)*size; int num_x_particle = 4+2*vmath::iround(cs::system_dimensions[0]/(grain_cell_size_x)); int num_y_particle = 4+2*vmath::iround(cs::system_dimensions[1]/(grain_cell_size_y)); int init_num_grains = num_x_particle*num_y_particle*2; // Define initial grain arrays std::vector <std::vector <double> > grain_coord_array; std::vector <std::vector <std::vector <double> > > grain_vertices_array; // Reserve space for pointers grain_coord_array.reserve(init_num_grains); grain_vertices_array.reserve(init_num_grains); // Calculate pointers for(int grain=0;grain<init_num_grains;grain++){ grain_coord_array.push_back(std::vector <double>()); grain_coord_array[grain].reserve(2); grain_vertices_array.push_back(std::vector <std::vector <double> >()); //for(int vertex=0;vertex<max_vertices;vertex++){ // grain_vertices_array[grain].push_back(std::vector <double>()); // grain_vertices_array[grain][vertex].reserve(2); //} //std::cout << grain_vertices_array[grain].size() << " " << grain_vertices_array[grain].capacity() << std::endl; } //std::cin.get(); double delta_particle_x = grain_cell_size_x; double delta_particle_y = grain_cell_size_y; double delta_particle_x_parity = delta_particle_x*0.5; double delta_particle_y_parity = delta_particle_y*0.5; // Set voronoi seed; mtrandom::grnd.seed(mtrandom::voronoi_seed); // Loop to generate hexagonal lattice points double particle_coords[2]; int vp=int(create_voronoi::parity); int grain=0; for (int x_particle=0;x_particle < num_x_particle;x_particle++){ for (int y_particle=0;y_particle < num_y_particle;y_particle++){ for (int particle_parity=0;particle_parity<2;particle_parity++){ //particle_coords[0] = (particle_parity)*delta_particle_x_parity + delta_particle_x*x_particle-size + vp*double(1-2*particle_parity)*delta_particle_x_parity; //particle_coords[1] = (particle_parity)*delta_particle_y_parity + delta_particle_y*y_particle-size; particle_coords[0] = (particle_parity)*delta_particle_x_parity + delta_particle_x*x_particle + vp*double(1-2*particle_parity)*delta_particle_x_parity; particle_coords[1] = (particle_parity)*delta_particle_y_parity + delta_particle_y*y_particle; grain_coord_array[grain].push_back(particle_coords[0]+grain_sd*mtrandom::gaussian()*delta_particle_x); grain_coord_array[grain].push_back(particle_coords[1]+grain_sd*mtrandom::gaussian()*delta_particle_y); grain++; } } } //----------------------- // Check for grains >=1 //----------------------- if(grain<1){ terminaltextcolor(RED); std::cerr << "Error! - No grains found in structure - Increase system dimensions" << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Error! - No grains found in structure - Increase system dimensions" << std::endl; err::vexit(); } // Calculate Voronoi construction using qhull removing boundary grains (false) create::internal::populate_vertex_points(grain_coord_array, grain_vertices_array, false); // Shrink Voronoi vertices in reduced coordinates to get spacing double shrink_factor = create::internal::voronoi_grain_size/(create::internal::voronoi_grain_size+create::internal::voronoi_grain_spacing); // Reduce vertices to relative coordinates for(unsigned int grain=0;grain<grain_coord_array.size();grain++){ //grain_coord_array[grain][0]=0.0; //grain_coord_array[grain][1]=0.0; const int nv = grain_vertices_array[grain].size(); // Exclude grains with zero vertices if(nv!=0){ for(int vertex=0;vertex<nv;vertex++){ double vc[2]; // vertex coordinates vc[0]=shrink_factor*(grain_vertices_array[grain][vertex][0]-grain_coord_array[grain][0]); vc[1]=shrink_factor*(grain_vertices_array[grain][vertex][1]-grain_coord_array[grain][1]); grain_vertices_array[grain][vertex][0]=vc[0]; grain_vertices_array[grain][vertex][1]=vc[1]; } } } // round grains if necessary if(create_voronoi::rounded) create::internal::voronoi_grain_rounding(grain_coord_array, grain_vertices_array); // Create a 2D supercell array of atom numbers to improve performance for systems with many grains std::vector < std::vector < std::vector < int > > > supercell_array; int min_bounds[3]; int max_bounds[3]; min_bounds[0]=0; min_bounds[1]=0; min_bounds[2]=0; max_bounds[0]=cs::total_num_unit_cells[0]; max_bounds[1]=cs::total_num_unit_cells[1]; max_bounds[2]=cs::total_num_unit_cells[2]; // allocate supercell array int dx = max_bounds[0]-min_bounds[0]; int dy = max_bounds[1]-min_bounds[1]; supercell_array.resize(dx); for(int i=0;i<dx;i++) supercell_array[i].resize(dy); // loop over atoms and populate supercell array for(unsigned int atom=0;atom<catom_array.size();atom++){ int cx = int (catom_array[atom].x/unit_cell.dimensions[0]); int cy = int (catom_array[atom].y/unit_cell.dimensions[1]); supercell_array.at(cx).at(cy).push_back(atom); } // Determine order for core-shell grains std::list<create::internal::core_radius_t> material_order(0); for(int mat=0;mat<mp::num_materials;mat++){ create::internal::core_radius_t tmp; tmp.mat=mat; tmp.radius=mp::material[mat].core_shell_size; material_order.push_back(tmp); } // sort by increasing radius material_order.sort(create::internal::compare_radius); std::cout <<"Generating Voronoi Grains"; zlog << zTs() << "Generating Voronoi Grains"; // arrays to store list of grain vertices double tmp_grain_pointx_array[max_vertices]; double tmp_grain_pointy_array[max_vertices]; // loop over all grains with vertices for(unsigned int grain=0;grain<grain_coord_array.size();grain++){ // Exclude grains with zero vertices if((grain%(grain_coord_array.size()/10))==0){ std::cout << "." << std::flush; zlog << "." << std::flush; } if(grain_vertices_array[grain].size()!=0){ // initialise minimum and max supercell coordinates for grain int minx=10000000; int maxx=0; int miny=10000000; int maxy=0; // Set temporary vertex coordinates (real) and compute cell ranges int num_vertices = grain_vertices_array[grain].size(); for(int vertex=0;vertex<num_vertices;vertex++){ // determine vertex coordinates tmp_grain_pointx_array[vertex]=grain_vertices_array[grain][vertex][0]; tmp_grain_pointy_array[vertex]=grain_vertices_array[grain][vertex][1]; // determine unit cell coordinates encompassed by grain int x = int((tmp_grain_pointx_array[vertex]+grain_coord_array[grain][0])/unit_cell.dimensions[0]); int y = int((tmp_grain_pointy_array[vertex]+grain_coord_array[grain][1])/unit_cell.dimensions[1]); if(x < minx) minx = x; if(x > maxx) maxx = x; if(y < miny) miny = y; if(y > maxy) maxy = y; } // determine coordinate offset for grains const double x0 = grain_coord_array[grain][0]; const double y0 = grain_coord_array[grain][1]; // loopover cells for(int i=minx;i<=maxx;i++){ for(int j=miny;j<=maxy;j++){ // loop over atoms in cells; for(unsigned int id=0;id<supercell_array[i][j].size();id++){ int atom = supercell_array[i][j][id]; // Get atomic position double x = catom_array[atom].x; double y = catom_array[atom].y; if(mp::material[catom_array[atom].material].core_shell_size>0.0){ // Iterate over materials for(std::list<create::internal::core_radius_t>::iterator it = material_order.begin(); it != material_order.end(); it++){ int mat = (it)->mat; double factor = mp::material[mat].core_shell_size; double maxz=create::internal::mp[mat].max*cs::system_dimensions[2]; double minz=create::internal::mp[mat].min*cs::system_dimensions[2]; double cz=catom_array[atom].z; const int atom_uc_cat = catom_array[atom].uc_category; const int mat_uc_cat = create::internal::mp[mat].unit_cell_category; // check for within core shell range if(vmath::point_in_polygon_factor(x-x0,y-y0,factor, tmp_grain_pointx_array,tmp_grain_pointy_array,num_vertices)==true){ if((cz>=minz) && (cz<maxz) && (atom_uc_cat == mat_uc_cat) ){ catom_array[atom].include=true; catom_array[atom].material=mat; catom_array[atom].grain=grain; } // if set to clear atoms then remove atoms within radius else if(cs::fill_core_shell==false){ catom_array[atom].include=false; } } } } // Check to see if site is within polygon else if(vmath::point_in_polygon_factor(x-x0,y-y0,1.0,tmp_grain_pointx_array,tmp_grain_pointy_array,num_vertices)==true){ catom_array[atom].include=true; catom_array[atom].grain=grain; } } } } } } terminaltextcolor(GREEN); std::cout << "done!" << std::endl; terminaltextcolor(WHITE); zlog << "done!" << std::endl; // add final grain for continuous layer grain_coord_array.push_back(std::vector <double>()); grain_coord_array[grain_coord_array.size()-1].push_back(0.0); // x grain_coord_array[grain_coord_array.size()-1].push_back(0.0); // y // check for continuous layer for(unsigned int atom=0; atom < catom_array.size(); atom++){ if(mp::material[catom_array[atom].material].continuous==true && catom_array[atom].include == false ){ catom_array[atom].include=true; catom_array[atom].grain=int(grain_coord_array.size()-1); } } // set number of grains grains::num_grains = int(grain_coord_array.size()); // sort atoms by grain number sort_atoms_by_grain(catom_array); return EXIT_SUCCESS; }