// zexit with error message void zexit(std::string message){ // check calling of routine if error checking is activated if(err::check==true){std::cout << "err::zexit(std::string) has been called" << std::endl;} // Abort MPI processes for parallel execution #ifdef MPICF std::cerr << "Fatal error on rank " << vmpi::my_rank << ": " << message << std::endl; std::cerr << "Aborting program." << std::endl; zlog << zTs() << "Fatal error on rank " << vmpi::my_rank << ": " << message << std::endl; zlog << zTs() << "Aborting program." << std::endl; // concatenate log and sort #ifdef WIN_COMPILE system("type log.* 2>NUL | sort > log"); #else system("ls log.* | xargs cat | sort -n > log"); #endif MPI::COMM_WORLD.Abort(EXIT_FAILURE); // MPI program dies ungracefully here #else // Print Error message to screen and log std::cerr << "Fatal error: " << message << std::endl; zlog << zTs() << "Fatal error: " << message << std::endl; #endif // Print error message to screen and log zlog << zTs() << "Aborting program." << std::endl; std::cout << "Aborting program. See log file for details." << std::endl; // Now exit program disgracefully exit(EXIT_FAILURE); }
//------------------------------------------------------------------------------------------------------ // Function to initialize data structures //------------------------------------------------------------------------------------------------------ void susceptibility_statistic_t::initialize(stats::magnetization_statistic_t& mag_stat) { // Check that magnetization statistic is properly initialized if(!mag_stat.is_initialized()){ terminaltextcolor(RED); std::cerr << "Programmer Error - Uninitialized magnetization statistic passed to susceptibility statistic - please initialize first." << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Programmer Error - Uninitialized magnetization statistic passed to susceptibility statistic - please initialize first." << std::endl; err::vexit(); } // Determine number of magnetization statistics*4 std::vector<double> temp = mag_stat.get_magnetization(); num_elements = temp.size()/4; // Now set number of susceptibility values to match mean_susceptibility.resize(4*num_elements,0.0); mean_susceptibility_squared.resize(4*num_elements,0.0); mean_absolute_susceptibility.resize(4*num_elements,0.0); mean_absolute_susceptibility_squared.resize(4*num_elements,0.0); // copy saturation data saturation = mag_stat.saturation; // initialize mean counter mean_counter = 0.0; // Set flag indicating correct initialization initialized=true; }
//--------------------------------------------------------------------------- // Function to process material parameters //--------------------------------------------------------------------------- bool match_material_parameter(std::string const word, std::string const value, std::string const unit, int const line, int const super_index, const int sub_index, const int max_materials){ // add prefix string std::string prefix="material:"; // Check for empty material parameter array and resize to avoid segmentation fault if(internal::mp.size() == 0){ internal::mp.resize(max_materials); } //------------------------------------------------------------ // Check for material properties //------------------------------------------------------------ std::string test = "dmi-constant"; // short form std::string test2 = "dzyaloshinskii-moriya-interaction-constant"; // long form if( (word == test) || (word == test2) ){ double dmi = atof(value.c_str()); vin::check_for_valid_value(dmi, word, line, prefix, unit, "energy", -1e-17, 1e-17,"material"," < +/- 1.0e17"); internal::mp[super_index].dmi[sub_index] = dmi; internal::enable_dmi = true; // Switch on dmi calculation and fully unrolled tensorial anisotropy return true; } test = "exchange-matrix"; if(word==test){ // extract comma separated values from string std::vector<double> Jij = vin::doubles_from_string(value); if(Jij.size() == 1){ vin::check_for_valid_value(Jij[0], word, line, prefix, unit, "energy", -1e-18, 1e-18,"material"," < +/- 1.0e18"); // set all components in case vectorial form is needed later vin::read_material[super_index].Jij_matrix_SI[sub_index][0] = Jij[0]; // Import exchange as field vin::read_material[super_index].Jij_matrix_SI[sub_index][1] = Jij[0]; vin::read_material[super_index].Jij_matrix_SI[sub_index][2] = Jij[0]; return true; } else if(Jij.size() == 3){ vin::check_for_valid_vector(Jij, word, line, prefix, unit, "energy", -1e-18, 1e-18,"material"," < +/- 1.0e18"); vin::read_material[super_index].Jij_matrix_SI[sub_index][0] = Jij[0]; // Import exchange as field vin::read_material[super_index].Jij_matrix_SI[sub_index][1] = Jij[1]; vin::read_material[super_index].Jij_matrix_SI[sub_index][2] = Jij[2]; // set vectorial anisotropy internal::exchange_type = internal::vectorial; return true; } else{ terminaltextcolor(RED); std::cerr << "Error in input file - material[" << super_index << "]:exchange_matrix[" << sub_index << "] must have one or three values." << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Error in input file - material[" << super_index << "]:exchange_matrix[" << sub_index << "] must have one or three values." << std::endl; err::vexit(); return false; } } //-------------------------------------------------------------------- // Keyword not found //-------------------------------------------------------------------- return false; }
//------------------------------------------------------------------------------- // Function to initialize create module //------------------------------------------------------------------------------- void initialize(){ // If create material parameters uninitialised then initialise with default parameters if(create::internal::mp.size() == 0){ create::internal::mp.resize(mp::num_materials); } // Loop over materials to check for invalid input and warn appropriately for(int mat=0;mat<mp::num_materials;mat++){ const double lmin=create::internal::mp[mat].min; const double lmax=create::internal::mp[mat].max; for(int nmat=0;nmat<mp::num_materials;nmat++){ if(nmat!=mat){ double min=create::internal::mp[nmat].min; double max=create::internal::mp[nmat].max; if(((lmin>min) && (lmin<max)) || ((lmax>min) && (lmax<max))){ terminaltextcolor(RED); std::cerr << "Warning: Overlapping material heights found. Check log for details." << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Warning: material " << mat+1 << " overlaps material " << nmat+1 << "." << std::endl; zlog << zTs() << "If you have defined geometry then this may be OK, or possibly you meant to specify alloy keyword instead." << std::endl; zlog << zTs() << "----------------------------------------------------" << std::endl; zlog << zTs() << " Material "<< mat+1 << ":minimum-height = " << lmin << std::endl; zlog << zTs() << " Material "<< mat+1 << ":maximum-height = " << lmax << std::endl; zlog << zTs() << " Material "<< nmat+1 << ":minimum-height = " << min << std::endl; zlog << zTs() << " Material "<< nmat+1 << ":maximum-height = " << max << std::endl; } } } } return; }
//-------------------------------------------------- // Add point to list of input points // void lattice_anis_t::add_point(double temperature, double anisotropy){ // check for valid temperature value if( temperature < 0.0 && temperature > 10000.0 ){ std::cerr << "Error: Temperature value " << temperature << " in lattice anisotropy file is invalid. Temperature values must be in the range 0 - 10000 K. Exiting." << std::endl; zlog << zTs() << "Error: Temperature value " << temperature << " in lattice anisotropy file is invalid. Temperature values must be in the range 0 - 10000 K. Exiting." << std::endl; err::vexit(); } // add values to list T.push_back(temperature); k.push_back(anisotropy); return; }
/// Main function for vampire /// Prints out program header and calls main program routines int main(int argc, char* argv[]){ //============================================================= // Check for valid command-line arguments //============================================================= std::string infile="input"; for(int arg = 1; arg < argc; arg++){ std::string sw=argv[arg]; // input file if(sw=="-f"){ // check number of args not exceeded if(arg+1 < argc){ arg++; infile=string(argv[arg]); } else{ std::cerr << "Error - no file specified for \'-f\' command line option" << std::endl; return EXIT_FAILURE; } } else{ std::cerr << "Error - unknown command line parameter \'" << sw << "\'" << std::endl; return EXIT_FAILURE; } } // For parallel execution intialise MPI #ifdef MPICF vmpi::initialise(); #endif // Initialise log file vout::zLogTsInit(std::string(argv[0])); // Output Program Header if(vmpi::my_rank==0){ std::cout << " _ " << std::endl; std::cout << " (_) " << std::endl; std::cout << " __ ____ _ _ __ ___ _ __ _ _ __ ___ " << std::endl; std::cout << " \\ \\ / / _` | '_ ` _ \\| '_ \\| | '__/ _ \\" << std::endl; std::cout << " \\ V / (_| | | | | | | |_) | | | | __/" << std::endl; std::cout << " \\_/ \\__,_|_| |_| |_| .__/|_|_| \\___|" << std::endl; std::cout << " | | " << std::endl; std::cout << " |_| " << std::endl; std::cout << std::endl; std::cout << " Version 3.0.3 " << __DATE__ << " " << __TIME__ << std::endl; std::cout << std::endl; std::cout << " Licensed under the GNU Public License(v2). See licence file for details." << std::endl; std::cout << std::endl; std::cout << " Lead Developer: Richard F L Evans <*****@*****.**>" << std::endl; std::cout << std::endl; std::cout << " Contributors: Weijia Fan, Phanwadee Chureemart, Joe Barker, " << std::endl; std::cout << " Thomas Ostler, Andreas Biternas, Roy W Chantrell" << std::endl; std::cout << " " << std::endl; #ifdef COMP std::cout << " Compiled with: " << COMP << std::endl; #endif std::cout << " Compiler Flags: "; #ifdef CUDA std::cout << "CUDA "; #endif #ifdef MPICF std::cout << "MPI "; #endif std::cout << std::endl; std::cout << std::endl; std::cout << "================================================================================" << std::endl; time_t rawtime = time(NULL); struct tm * timeinfo = localtime(&rawtime); std::cout<<asctime(timeinfo); } #ifdef MPICF vmpi::hosts(); #endif #ifdef MPICF // nullify non root cout stream if(vmpi::my_rank!=0){ vout::nullify(std::cout); } #endif // Initialise system mp::initialise(infile); // Create system cs::create(); // Simulate system sim::run(); // Finalise MPI #ifdef MPICF vmpi::finalise(); // concatenate log, sort, and append departure message. #ifdef WIN_COMPILE if(vmpi::num_processors!=1 && vmpi::my_rank==0) system("type log.* 2>NUL | sort > log"); #else if(vmpi::num_processors!=1 && vmpi::my_rank==0) system("ls log.* | xargs cat | sort -n > log"); #endif #endif zlog << zTs() << "Simulation ended gracefully." << std::endl; std::cout << "Simulation ended gracefully." << std::endl; return EXIT_SUCCESS; }
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; }
//-------------------------------------------------- // Creates a lookup table of interpolated functions // to calculate lattice anisotropy // void lattice_anis_t::set_interpolation_table(){ // Output informative message to log zlog << zTs() << "Determining interpolation variables for tabulated lattice anisotropy." << std::endl; // Check for undefined lattice anisotropy if(T.size()==0){ Tmax=0; k_Tmax=0.0; return; } // check T(i+1) > T(i) for(unsigned int i=1; i<T.size(); i++){ if(T[i]<T[i-1]){ std::cerr << "Error: temperature value "<< T[i] <<" on line " << i+2 << " is less than the previous value " << T[i-1] << " and must be given in ascending order. Exiting" << std::endl; zlog << zTs() << "Error: temperature value "<< T[i] <<" on line " << i+2 << " is less than the previous value " << T[i-1] << " and must be given in ascending order. Exiting" << std::endl; err::vexit(); } } // loop over all temperatures up to Tmax and create temporary list of min, max, m and c values std::vector<double> tmin; std::vector<double> tmax; std::vector<double> tm; std::vector<double> tc; // start from i+1 for(unsigned int i=1; i<T.size(); i++){ tmin.push_back(T[i-1]); tmax.push_back(T[i]); tm.push_back(vmath::interpolate_m(T[i-1],k[i-1],T[i],k[i])); tc.push_back(vmath::interpolate_c(T[i-1],k[i-1],T[i],k[i])); } // determine maximum temperature specified in interpolation table Tmax=int(T[T.size()-1]); // resize interpolation array to size Tmax m.resize(Tmax,0.0); c.resize(Tmax,0.0); // determine last value of k at Tmax k_Tmax = k[k.size()-1]; // determine first value of k double k_Tmin = k[0]; double Tmin = T[0]; // loop over all values up to Tmax and substitute m and c interpolation for(unsigned int Ti=0; Ti<Tmax; Ti++){ // 1 Kelvin resolution bool found_mc=false; // Check for T<Tmin if(double(Ti)<double(Tmin)){ m[Ti] = 0; c[Ti] = k_Tmin; //mark valid value found found_mc = true; // move to next temperature value continue; } // loop over all possible values for(unsigned int mm=0; mm<tmin.size(); mm++){ double min = tmin[mm]; double max = tmax[mm]; // check if Ti is in temperature range if( double(Ti) >= min && double(Ti) < max ){ // copy interpolation values m[Ti] = tm[mm]; c[Ti] = tc[mm]; // mark valid function found found_mc = true; // move to next temperature value Ti break; } } // check for value not in range if(found_mc==false){ std::cerr << "Code error: Temperature value " << Ti << " in interpolation function is not within range specified in lattice-anisotropy-file. Exiting" << std::endl; zlog << zTs() << "Code error: Temperature value " << Ti << " in interpolation function is not within range specified in lattice-anisotropy-file. Exiting" << std::endl; err::vexit(); } } return; }
//--------------------------------------------------------------------------------------------------------------------- // Setting algorithm for exchange bias in IrMn3 //--------------------------------------------------------------------------------------------------------------------- void setting_process(){ //Arrays to determine the 8 possible ground state spin orientations configurations double Configurations[8][3] = { {0, 0, -1}, {-0.94, 0, 0.3}, {0.44, -0.845, 0.3}, {0.44, 0.845, 0.3}, {0, 0, 1}, {0.94, 0, -0.3}, {-0.44, 0.845, -0.3}, {-0.44, -0.845, -0.3} }; // List the 8 possible combinations of spin orientation double Possible_Arrays[8][4] = { {0,1,2,3}, {1,0,3,2}, {2,3,0,1}, {3,2,1,0}, {4,5,6,7}, {5,4,7,6}, {6,7,4,5}, {7,6,5,4} }; std::vector< std::vector <int> > No_in_Sublattice; // Number sublattices in each grain No_in_Sublattice.resize(4); // resize array for correct number of atoms in each grain // std::cout << grains::num_grains <<std::endl; for(int i = 0; i < 4; i++) No_in_Sublattice[i].resize(grains::num_grains,0.0); std::vector <int> Local_Sub (grains::num_grains*4,0); std::vector <int> Chosen_array(grains::num_grains,0); std::vector <int> Largest_Sublattice(grains::num_grains,0); std::vector <int> Max_atoms(grains::num_grains,0); #ifdef MPICF stats::num_atoms = vmpi::num_core_atoms+vmpi::num_bdry_atoms; #else stats::num_atoms = atoms::num_atoms; #endif std::cerr << "A" << stats::num_atoms << "\t" << grains::num_grains << std::endl; //Calculates how many atoms are in the top layer of each sublattice in each grain. for (int atom = 0; atom < stats::num_atoms; atom++){ for (int neighbour = atoms::neighbour_list_start_index[atom]; neighbour < atoms::neighbour_list_end_index[atom]; neighbour ++){ // explain what if statement is testing - yes Sarah... //std::cout << atom << "\t" << neighbour <<atoms::type_array[atom] << '\t' << atoms::type_array[atoms::neighbour_list_array[neighbour]] << std::endl; if ((atoms::type_array[atom] >3) && (atoms::type_array[atoms::neighbour_list_array[neighbour]] < 4)){ // std::cerr << atoms::grain_array[atom] << "\t"<< atoms::type_array[atoms::neighbour_list_array[neighbour]] << "\t" << atoms::type_array[atom] <<endl; No_in_Sublattice[atoms::type_array[atoms::neighbour_list_array[neighbour]]][atoms::grain_array[atom]]++; // cerr << No_in_Sublattice[atoms::type_array[atoms::neighbour_list_array[neighbour]]][atoms::grain_array[atom]]<<endl; } } } int k = 0; for (int j = 0; j < grains::num_grains; j ++){ for (int i = 0; i < 4; i ++){ Local_Sub[k] = No_in_Sublattice[i][j]; k++; } } std::cerr << "before" << Local_Sub[0] << '\t' << Local_Sub[1] << '\t' << Local_Sub[2] << '\t' << Local_Sub[3] << std::endl; #ifdef MPICF MPI_Allreduce(MPI_IN_PLACE, &Local_Sub[0],grains::num_grains*4,MPI_INT,MPI_SUM, MPI_COMM_WORLD); #endif std::cerr<< "after" << Local_Sub[0] << '\t' << Local_Sub[1] << '\t' << Local_Sub[2] << '\t' << Local_Sub[3] << std::endl; int l =0; //calculates which sublattice contains the most atoms for each grain. for (int j = 0; j < grains::num_grains; j++){ for( int i = 0; i <4; i ++){ // std::cout << Local_Sub[l] << "\t" << Local_Sub[l] << std::endl; if ((Local_Sub[l] > Max_atoms[j]) & (Local_Sub[l] != 0)){ Largest_Sublattice[j] = i; Max_atoms[j] =Local_Sub[l]; } l++; } if (Local_Sub[l-1] !=0 ) cerr << Largest_Sublattice[j] <<endl; } int j = 0; for (int i = 0; i < grains::num_grains*4; i= i +4){ if (Local_Sub[i] != 0){ cerr <<"number in each sublattice for grain" << j << ";" << Local_Sub[i] << "\t" << Local_Sub[i +1] << "\t" << Local_Sub[i+2] << "\t" << Local_Sub[i+3] << "\t" << std::endl; zlog << zTs() <<"number in each sublattice for grain" << j << ";" << Local_Sub[i] << "\t" << Local_Sub[i +1] << "\t" << Local_Sub[i+2] << "\t" << Local_Sub[i+3] << "\t" << std::endl; j++; } } double result,angle; double min_angle = 1000; double Direction_Closest_to_Field; //Loop over all possible combinations to calculate which possible vector is closest to the applied field. for (int i = 0; i < 8; i ++){ result = Configurations[i][0]*sim::H_vec[0] + Configurations[i][1]*sim::H_vec[1] + Configurations[i][2]*sim::H_vec[2]; angle = acos(result); //Calculates the minimum angle between the applied field and the spin directions. if ( angle< min_angle){ Direction_Closest_to_Field = i; min_angle = angle; } } // std::cout << Direction_Closest_to_Field <<std::endl; //Sets the sublattice with the largest number of atoms along the direction nearest the field //This minimises S.H for (int j = 0; j < grains::num_grains; j ++){ for (int i = 0; i <8; i ++){ if (Possible_Arrays[i][Largest_Sublattice[j]] == Direction_Closest_to_Field){ // std::cout << i <<std::endl; Chosen_array[j] = i; break; } } } std::cout << "a" <<std::endl; for (int i = 0; i <stats::num_atoms; i++){ // std::cout << atoms::type_array[i] << "\t" << atoms::z_spin_array[i] <<std::endl; if(atoms::type_array[i] > 3){ atoms::x_spin_array[i] = sim::H_vec[0]; atoms::y_spin_array[i] = sim::H_vec[1]; atoms::z_spin_array[i] = sim::H_vec[2]; } else { int Array = Possible_Arrays[Chosen_array[atoms::grain_array[i]]][atoms::type_array[i]]; atoms::x_spin_array[i] = Configurations[Array][0]; atoms::y_spin_array[i] = Configurations[Array][1]; atoms::z_spin_array[i] = Configurations[Array][2]; } } // Calculate magnetisation statistics stats::mag_m(); // Output data vout::data(); }
/// @brief Cell initialiser function /// /// @details Determines number of cells, assigns atoms to cells, and sets up cell arrays /// /// @section License /// Use of this code, either in source or compiled form, is subject to license from the authors. /// Copyright \htmlonly © \endhtmlonly Richard Evans, 2009-2011. All Rights Reserved. /// /// @section Information /// @author Richard Evans, [email protected] /// @version 1.0 /// @date 28/03/2011 /// /// @return EXIT_SUCCESS /// /// @internal /// Created: 05/02/2011 /// Revision: --- ///===================================================================================== /// int initialise(){ // check calling of routine if error checking is activated if(err::check==true) std::cout << "cells::initialise has been called" << std::endl; cells::num_cells=0; cells::num_local_cells=0; zlog << zTs() << "Cell size = " << cells::size << std::endl; // determine number of cells in each direction (with small shift to prevent the fence post problem) unsigned int ncellx = static_cast<unsigned int>(ceil((cs::system_dimensions[0]+0.01)/cells::size)); unsigned int ncelly = static_cast<unsigned int>(ceil((cs::system_dimensions[1]+0.01)/cells::size)); unsigned int ncellz = static_cast<unsigned int>(ceil((cs::system_dimensions[2]+0.01)/cells::size)); //update total number of cells cells::num_cells=ncellx*ncelly*ncellz; zlog << zTs() << "Cells in x,y,z: " << ncellx << "\t" << ncelly << "\t" << ncellz << std::endl; zlog << zTs() << "Total number of cells: " << cells::num_cells << std::endl; zlog << zTs() << "Memory required for cell arrays: " << 80.0*double(cells::num_cells)/1.0e6 << " MB" << std::endl; // Determine number of cells in x,y,z const int d[3]={ncellx,ncelly,ncellz}; // Set cell counter int cell=0; // Declare array for create space for 3D supercell array int*** supercell_array; //std::cout << "Memory required for cell list calculation:" << 8.0*double(d[0])*double(d[1])*double(d[2])/1.0e6 << " MB" << std::endl; try{supercell_array=new int**[d[0]]; for(int i=0; i<d[0] ; i++){ supercell_array[i]=new int*[d[1]]; for(int j=0; j<d[1] ; j++){ supercell_array[i][j]=new int[d[2]]; for(int k=0; k<d[2] ; k++){ supercell_array[i][j][k]=cell; cell++; } } } } catch(...){std::cerr << "Error allocating supercell_array for cell list calculation" << std::endl;err::vexit();} // slightly offset atomic coordinates to prevent fence post problem double atom_offset[3]={0.01,0.01,0.01}; // For MPI version, only add local atoms #ifdef MPICF int num_local_atoms = vmpi::num_core_atoms+vmpi::num_bdry_atoms; #else int num_local_atoms = atoms::num_atoms; #endif // Assign atoms to cells for(int atom=0;atom<num_local_atoms;atom++){ double c[3]={atoms::x_coord_array[atom]+atom_offset[0],atoms::y_coord_array[atom]+atom_offset[1],atoms::z_coord_array[atom]+atom_offset[2]}; int scc[3]={0,0,0}; // super cell coordinates for(int i=0;i<3;i++){ scc[i]=int(c[i]/cells::size); // Always round down for supercell coordinates // Always check cell in range if(scc[i]<0 || scc[i]>= d[i]){ std::cerr << "Error - atom out of supercell range in neighbourlist calculation!" << std::endl; #ifdef MPICF std::cerr << "\tCPU Rank: " << vmpi::my_rank << std::endl; #endif std::cerr << "\tAtom number: " << atom << std::endl; std::cerr << "\tAtom coordinates: " << c[0] << "\t" << c[1] << "\t" << c[2] << "\t" << std::endl; std::cerr << "\tCell coordinates: " << scc[0] << "\t" << scc[1] << "\t" << scc[2] << "\t" << std::endl; std::cerr << "\tCell maxima: " << d[0] << "\t" << d[1] << "\t" << d[2] << std::endl; err::vexit(); } } // If no error for range then assign atom to cell. atoms::cell_array[atom]=supercell_array[scc[0]][scc[1]][scc[2]]; } // Deallocate supercell array try{ for(int i=0; i<d[0] ; i++){ for(int j=0; j<d[1] ;j++){ delete [] supercell_array[i][j]; } delete [] supercell_array[i]; } delete [] supercell_array; supercell_array=NULL; } catch(...){zlog << zTs() << "error deallocating supercell_array" << std::endl; err::vexit();} // Resize new cell arrays cells::x_coord_array.resize(cells::num_cells,0.0); cells::y_coord_array.resize(cells::num_cells,0.0); cells::z_coord_array.resize(cells::num_cells,0.0); cells::x_mag_array.resize(cells::num_cells,0.0); cells::y_mag_array.resize(cells::num_cells,0.0); cells::z_mag_array.resize(cells::num_cells,0.0); cells::x_field_array.resize(cells::num_cells,0.0); cells::y_field_array.resize(cells::num_cells,0.0); cells::z_field_array.resize(cells::num_cells,0.0); cells::num_atoms_in_cell.resize(cells::num_cells,0); cells::volume_array.resize(cells::num_cells,0.0); std::vector<double> total_moment_array(cells::num_cells,0.0); // Now add atoms to each cell as magnetic 'centre of mass' for(int atom=0;atom<num_local_atoms;atom++){ int local_cell=atoms::cell_array[atom]; int type = atoms::type_array[atom]; const double mus = mp::material[type].mu_s_SI; cells::x_coord_array[local_cell]+=atoms::x_coord_array[atom]*mus; cells::y_coord_array[local_cell]+=atoms::y_coord_array[atom]*mus; cells::z_coord_array[local_cell]+=atoms::z_coord_array[atom]*mus; total_moment_array[local_cell]+=mus; cells::num_atoms_in_cell[local_cell]++; } // For MPI sum coordinates from all CPUs #ifdef MPICF MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE,&cells::num_atoms_in_cell[0],cells::num_cells,MPI_INT,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE,&cells::x_coord_array[0],cells::num_cells,MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE,&cells::y_coord_array[0],cells::num_cells,MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE,&cells::z_coord_array[0],cells::num_cells,MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE,&total_moment_array[0],cells::num_cells,MPI_DOUBLE,MPI_SUM); #endif //if(vmpi::my_rank==0){ //vinfo << "=========================================================================" << std::endl; //vinfo << "Number of atoms/cell: cell number, num atoms, coord" << std::endl; //vinfo << "=========================================================================" << std::endl; //} // Used to calculate magnetisation in each cell. Poor approximation when unit cell size ~ system size. const double atomic_volume = cs::unit_cell.dimensions[0]*cs::unit_cell.dimensions[1]*cs::unit_cell.dimensions[2]/cells::num_atoms_in_unit_cell; // Now find mean coordinates via magnetic 'centre of mass' for(int local_cell=0;local_cell<cells::num_cells;local_cell++){ if(cells::num_atoms_in_cell[local_cell]>0){ cells::x_coord_array[local_cell] = cells::x_coord_array[local_cell]/(total_moment_array[local_cell]); cells::y_coord_array[local_cell] = cells::y_coord_array[local_cell]/(total_moment_array[local_cell]); cells::z_coord_array[local_cell] = cells::z_coord_array[local_cell]/(total_moment_array[local_cell]); cells::volume_array[local_cell] = double(cells::num_atoms_in_cell[local_cell])*atomic_volume; } //if(vmpi::my_rank==0){ //vinfo << local_cell << "\t" << cells::num_atoms_in_cell[local_cell] << "\t"; //vinfo << cells::x_coord_array[local_cell] << "\t" << cells::y_coord_array[local_cell]; //vinfo << "\t" << cells::z_coord_array[local_cell] << "\t" << std::endl; //} } //Set number of atoms in cell to zero for(int cell=0;cell<cells::num_cells;cell++){ cells::num_atoms_in_cell[cell]=0; } // Now re-update num_atoms in cell for local atoms only for(int atom=0;atom<num_local_atoms;atom++){ int local_cell=atoms::cell_array[atom]; cells::num_atoms_in_cell[local_cell]++; } // Calculate number of local cells for(int cell=0;cell<cells::num_cells;cell++){ if(cells::num_atoms_in_cell[cell]!=0){ cells::local_cell_array.push_back(cell); cells::num_local_cells++; } } zlog << zTs() << "Number of local cells on rank " << vmpi::my_rank << ": " << cells::num_local_cells << std::endl; cells::initialised=true; // Precalculate cell magnetisation cells::mag(); return EXIT_SUCCESS; }
//------------------------------------------------------------------------------ // Function to calculate neighbour interactions assuming fractional unit cell //------------------------------------------------------------------------------ void calculate_interactions(unit_cell_t& unit_cell){ // determine neighbour range const double rcut = unit_cell.cutoff_radius*exchange_interaction_range*1.001; // reduced to unit cell units const double rcutsq = rcut*rcut; // reduced to unit cell units // temporary for unit cell size const double ucsx = unit_cell.dimensions[0]; const double ucsy = unit_cell.dimensions[1]; const double ucsz = unit_cell.dimensions[2]; // determine number of unit cells in x,y and z const int nx = 1 + 2*ceil(rcut); // number of replicated cells in x,y,z const int ny = 1 + 2*ceil(rcut); const int nz = 1 + 2*ceil(rcut); zlog << zTs() << "Generating neighbour interactions for a lattice of " << nx << " x " << ny << " x " << nz << " unit cells for neighbour calculation" << std::endl; // temporary array for replicated atoms std::vector<local::atom_t> ratoms; // replicate in x,y,z for(int x = 0; x < nx; ++x){ for(int y = 0; y < ny; ++y){ for(int z = 0; z < nz; ++z){ for(int a=0; a < unit_cell.atom.size(); ++a){ local::atom_t tmp; tmp.mat = unit_cell.atom[a].mat; tmp.x = (unit_cell.atom[a].x + double(x))*ucsx; tmp.y = (unit_cell.atom[a].y + double(y))*ucsy; tmp.z = (unit_cell.atom[a].z + double(z))*ucsz; tmp.id = a; tmp.idx = x; // unit cell id tmp.idy = y; tmp.idz = z; ratoms.push_back(tmp); } } } } // calculate neighbours and exchange for central cell int mid_cell_x = (nx-1)/2; int mid_cell_y = (ny-1)/2; int mid_cell_z = (nz-1)/2; const double nnrcut_sq = unit_cell.cutoff_radius*unit_cell.cutoff_radius*1.001*1.001; // nearest neighbour cutoff radius // loop over all i atoms for(int i=0; i < ratoms.size(); ++i){ // check for i atoms only in central cell if( (ratoms[i].idx == mid_cell_x) && (ratoms[i].idy == mid_cell_y) && (ratoms[i].idz == mid_cell_z) ){ // loop over all j atoms for(int j=0; j < ratoms.size(); ++j){ // calculate interatomic radius_sq const double rx = ratoms[j].x - ratoms[i].x; const double ry = ratoms[j].y - ratoms[i].y; const double rz = ratoms[j].z - ratoms[i].z; double range_sq = rx*rx + ry*ry + rz*rz; // check for rij < rcut and i!= j if( range_sq < rcutsq && i != j ){ // Neighbour found uc::interaction_t tmp; // Determine unit cell id for i and j atoms tmp.i = ratoms[i].id; tmp.j = ratoms[j].id; // Determine unit cell offsets tmp.dx = ratoms[j].idx - ratoms[i].idx; tmp.dy = ratoms[j].idy - ratoms[i].idy; tmp.dz = ratoms[j].idz - ratoms[i].idz; // save interaction range tmp.rij = sqrt(range_sq); // Determine normalised exchange constants tmp.Jij[0][0] = uc::internal::exchange(range_sq, nnrcut_sq); // xx tmp.Jij[0][1] = 0.0; // xy tmp.Jij[0][2] = 0.0; // xz tmp.Jij[1][0] = 0.0; // yx tmp.Jij[1][1] = uc::internal::exchange(range_sq, nnrcut_sq); // yy tmp.Jij[1][2] = 0.0; // yz tmp.Jij[2][0] = 0.0; // zx tmp.Jij[2][1] = 0.0; // zy tmp.Jij[2][2] = uc::internal::exchange(range_sq, nnrcut_sq); // zz unit_cell.interaction.push_back(tmp); } } } } // Set calculated interactions range int interaction_range=0; for(int i=0; i<unit_cell.interaction.size(); i++){ if(abs(unit_cell.interaction[i].dx)>interaction_range) interaction_range=abs(unit_cell.interaction[i].dx); if(abs(unit_cell.interaction[i].dy)>interaction_range) interaction_range=abs(unit_cell.interaction[i].dy); if(abs(unit_cell.interaction[i].dz)>interaction_range) interaction_range=abs(unit_cell.interaction[i].dz); } unit_cell.interaction_range = interaction_range; // Normalise exchange interactions uc::internal::normalise_exchange(unit_cell); // Output interactions to screen /*for(int i=0; i<unit_cell.interaction.size(); i++){ std::cerr << i << "\t" << unit_cell.interaction[i].i << "\t" << unit_cell.interaction[i].j << "\t" << unit_cell.interaction[i].dx << "\t" << unit_cell.interaction[i].dy << "\t" << unit_cell.interaction[i].dz << "\t" << unit_cell.interaction[i].rij << "\t" << unit_cell.interaction[i].Jij[0][0] << std::endl; }*/ // Check for interactions if(unit_cell.interaction.size()==0){ terminaltextcolor(RED); std::cerr << "Error! No interactions generated for " << uc::internal::crystal_structure << " crystal structure. Try increasing the interaction range. Aborting." << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Error! No interactions generated for " << uc::internal::crystal_structure << " crystal structure. Try increasing the interaction range. Aborting." << std::endl; err::vexit(); } // Determine exchange type if(uc::internal::exchange_type == isotropic) unit_cell.exchange_type=-1; else if(uc::internal::exchange_type == vectorial) unit_cell.exchange_type=3; else{ terminaltextcolor(RED); std::cerr << "Programmer error! Exchange type " << uc::internal::exchange_type << " is not a recognised value!" << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Programmer error! Exchange type " << uc::internal::exchange_type << " is not a recognised value!" << std::endl; err::vexit(); } return; }
//------------------------------------------------------------------------------ // Function to output non-magnetic atomic positions to disk //------------------------------------------------------------------------------ void atoms_non_magnetic(){ //------------------------------------------------------------ // Determine non magnetic atoms to be outputted to coord list //------------------------------------------------------------ // array of atom numbers to be outputted std::vector<uint64_t> atom_list(0); // get output bounds const double minB[3] = {atoms_output_min[0] * cs::system_dimensions[0], atoms_output_min[1] * cs::system_dimensions[1], atoms_output_min[2] * cs::system_dimensions[2]}; const double maxB[3] = {atoms_output_max[0] * cs::system_dimensions[0], atoms_output_max[1] * cs::system_dimensions[1], atoms_output_max[2] * cs::system_dimensions[2]}; // Determine non magnetic atoms to be outputted to coord list for (uint64_t atom = 0; atom < cs::non_magnetic_atoms_array.size(); atom++){ const double cc[3] = {cs::non_magnetic_atoms_array[atom].x, cs::non_magnetic_atoms_array[atom].y, cs::non_magnetic_atoms_array[atom].z}; // check atom within output bounds if ( (cc[0] >= minB[0]) && (cc[0] <= maxB[0]) ){ if ( (cc[1] >= minB[1]) && (cc[1] <= maxB[1]) ){ if ( (cc[2] >= minB[2]) && (cc[2] <= maxB[2]) ){ atom_list.push_back(atom); //non-magnetic atoms } } } } //------------------------------------------------ // Create temporary buffers for atom information //------------------------------------------------ uint64_t num_local_atoms = atom_list.size(); uint64_t num_total_atoms = 0; // number of atoms across all processors #ifdef MPICF // calculate number of atoms to be output on all processors MPI_Allreduce(&num_local_atoms, &num_total_atoms, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD); #else num_total_atoms = num_local_atoms; #endif std::vector<int> atom_type_buffer(num_local_atoms); for(unsigned int atom = 0; atom < num_local_atoms; atom++) atom_type_buffer[atom] = cs::non_magnetic_atoms_array[ atom_list[atom] ].mat; std::vector<int> atom_category_buffer(num_local_atoms); for(unsigned int atom = 0; atom < num_local_atoms; atom++) atom_category_buffer[atom] = cs::non_magnetic_atoms_array[ atom_list[atom] ].cat; std::vector<double> atom_coord_buffer(3*num_local_atoms); for(unsigned int atom = 0; atom < num_local_atoms; atom++){ const uint64_t atom_id = atom_list[atom]; // get atom array index atom_coord_buffer[3*atom + 0] = cs::non_magnetic_atoms_array[atom_id].x; atom_coord_buffer[3*atom + 1] = cs::non_magnetic_atoms_array[atom_id].y; atom_coord_buffer[3*atom + 2] = cs::non_magnetic_atoms_array[atom_id].z; } //------------------------------------------ // Output Meta Data from root process //------------------------------------------ // set number of files // const int files = config::internal::num_io_groups; // unused variable if(config::internal::mode != legacy && vmpi::my_rank == 0){ config::internal::write_non_magnetic_meta(num_total_atoms); } //------------------------------------------ // Output coordinate data //------------------------------------------ // Determine output filename std::stringstream file_sstr; // set simple file name for single file output if(config::internal::num_io_groups == 1) file_sstr << "non-magnetic-atoms.data"; // otherwise set indexed files else file_sstr << "non-magnetic-atoms-" << std::setfill('0') << std::setw(6) << config::internal::io_group_id << ".data"; // convert string stream to string std::string filename = file_sstr.str(); // Calculate number of bytes to be written to disk const double data_size = double(num_total_atoms) * 1.0e-9 * (3.0*double(sizeof(double) + 2.0*double(sizeof(int)) ) ); // Output informative messages of actual data size to be outputed to disk (in binary mode) zlog << zTs() << "Total non-magnetic data filesize: " << 1000.0 * data_size << " MB" << std::endl; // Output informative message to log file on root process zlog << zTs() << "Outputting non-magnetic atomic coordinate file to disk "; // Variable for calculating output bandwidth double io_time = 1.0e-12; //----------------------------------------------------- // Parallel mode output //----------------------------------------------------- #ifdef MPICF // Determine io mode and call appropriate function for data switch(config::internal::mode){ // legacy case config::internal::legacy: break; case config::internal::mpi_io:{ vutil::vtimer_t timer; // instantiate timer MPI_File fh; // MPI file handle MPI_Status status; // MPI io status // convert filename to character string for output char *cfilename = (char*)filename.c_str(); // Open file on all processors MPI_File_open(MPI_COMM_WORLD, cfilename, MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh); // write number of atoms on root process if(vmpi::my_rank == 0) MPI_File_write(fh, &num_total_atoms, 1, MPI_UINT64_T, &status); // Calculate local byte offsets since MPI-IO is simple and doesn't update the file handle pointer after I/O MPI_Offset type_offset = config::internal::linear_offset + sizeof(uint64_t); MPI_Offset category_offset = config::internal::linear_offset + num_total_atoms * sizeof(int) + sizeof(uint64_t); MPI_Offset data_offset = config::internal::buffer_offset + 2 * num_total_atoms * sizeof(int) + sizeof(uint64_t); timer.start(); // start timer // Write data to disk MPI_File_write_at_all(fh, type_offset, &atom_type_buffer[0], atom_type_buffer.size(), MPI_INT, &status); MPI_File_write_at_all(fh, category_offset, &atom_category_buffer[0], atom_category_buffer.size(), MPI_INT, &status); MPI_File_write_at_all(fh, data_offset, &atom_coord_buffer[0], atom_coord_buffer.size(), MPI_DOUBLE, &status); timer.stop(); // Stop timer // Calculate elapsed time io_time = timer.elapsed_time(); // Close file MPI_File_close(&fh); break; } case config::internal::fpprocess: io_time = write_coord_data(filename, atom_coord_buffer, atom_type_buffer, atom_category_buffer); break; case config::internal::fpnode:{ // Gather data from all processors in io group std::vector<int> collated_atom_type_buffer(0); collate_int_data(atom_type_buffer, collated_atom_type_buffer); std::vector<int> collated_atom_category_buffer(0); collate_int_data(atom_category_buffer, collated_atom_category_buffer); std::vector<double> collated_atom_coord_buffer(0); collate_double_data(atom_coord_buffer, collated_atom_coord_buffer); // output data on master io processes if(config::internal::io_group_master) io_time = write_coord_data(filename, collated_atom_coord_buffer, collated_atom_type_buffer, collated_atom_category_buffer); // find longest time in all io nodes double max_io_time = 0.0; // calculate actual bandwidth on root process MPI_Reduce(&io_time, &max_io_time, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); io_time = max_io_time; break; } } #else //----------------------------------------------------- // Serial mode output (ignores most io directives) //----------------------------------------------------- // if new output (not legacy) then output non magnetic atoms if(config::internal::mode != config::internal::legacy) io_time = write_coord_data(filename, atom_coord_buffer, atom_type_buffer, atom_category_buffer); #endif // Output bandwidth to log file zlog << data_size/io_time << " GB/s in " << io_time << " s" << std::endl; return; }
int create_crystal_structure(std::vector<cs::catom_t> & catom_array){ //---------------------------------------------------------- // check calling of routine if error checking is activated //---------------------------------------------------------- if(err::check==true){std::cout << "cs::create_crystal_structure has been called" << std::endl;} int min_bounds[3]; int max_bounds[3]; #ifdef MPICF if(vmpi::mpi_mode==0){ min_bounds[0] = int(vmpi::min_dimensions[0]/unit_cell.dimensions[0]); min_bounds[1] = int(vmpi::min_dimensions[1]/unit_cell.dimensions[1]); min_bounds[2] = int(vmpi::min_dimensions[2]/unit_cell.dimensions[2]); max_bounds[0] = vmath::iceil(vmpi::max_dimensions[0]/unit_cell.dimensions[0]); max_bounds[1] = vmath::iceil(vmpi::max_dimensions[1]/unit_cell.dimensions[1]); max_bounds[2] = vmath::iceil(vmpi::max_dimensions[2]/unit_cell.dimensions[2]); } else{ 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]; } #else 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]; #endif cs::local_num_unit_cells[0]=max_bounds[0]-min_bounds[0]; cs::local_num_unit_cells[1]=max_bounds[1]-min_bounds[1]; cs::local_num_unit_cells[2]=max_bounds[2]-min_bounds[2]; int num_atoms=cs::local_num_unit_cells[0]*cs::local_num_unit_cells[1]*cs::local_num_unit_cells[2]*unit_cell.atom.size(); // set catom_array size catom_array.reserve(num_atoms); // Initialise atoms number int atom=0; // find maximum height lh_category unsigned int maxlh=0; for(unsigned int uca=0;uca<unit_cell.atom.size();uca++) if(unit_cell.atom[uca].hc > maxlh) maxlh = unit_cell.atom[uca].hc; maxlh+=1; const double cff = 1.e-9; // Small numerical correction for atoms exactly on the borderline between processors // Duplicate unit cell for(int z=min_bounds[2];z<max_bounds[2];z++){ for(int y=min_bounds[1];y<max_bounds[1];y++){ for(int x=min_bounds[0];x<max_bounds[0];x++){ // need to change this to accept non-orthogonal lattices // Loop over atoms in unit cell for(unsigned int uca=0;uca<unit_cell.atom.size();uca++){ double cx = (double(x)+unit_cell.atom[uca].x)*unit_cell.dimensions[0]+cff; double cy = (double(y)+unit_cell.atom[uca].y)*unit_cell.dimensions[1]+cff; double cz = (double(z)+unit_cell.atom[uca].z)*unit_cell.dimensions[2]+cff; #ifdef MPICF if(vmpi::mpi_mode==0){ // only generate atoms within allowed dimensions if( (cx>=vmpi::min_dimensions[0] && cx<vmpi::max_dimensions[0]) && (cy>=vmpi::min_dimensions[1] && cy<vmpi::max_dimensions[1]) && (cz>=vmpi::min_dimensions[2] && cz<vmpi::max_dimensions[2])){ #endif if((cx<cs::system_dimensions[0]) && (cy<cs::system_dimensions[1]) && (cz<cs::system_dimensions[2])){ catom_array.push_back(cs::catom_t()); catom_array[atom].x=cx; catom_array[atom].y=cy; catom_array[atom].z=cz; //std::cout << atom << "\t" << cx << "\t" << cy <<"\t" << cz << std::endl; catom_array[atom].material=unit_cell.atom[uca].mat; catom_array[atom].uc_id=uca; catom_array[atom].lh_category=unit_cell.atom[uca].hc+z*maxlh; catom_array[atom].uc_category=unit_cell.atom[uca].lc; catom_array[atom].scx=x; catom_array[atom].scy=y; catom_array[atom].scz=z; atom++; } #ifdef MPICF } } else{ if((cx<cs::system_dimensions[0]) && (cy<cs::system_dimensions[1]) && (cz<cs::system_dimensions[2])){ catom_array.push_back(cs::catom_t()); catom_array[atom].x=cx; catom_array[atom].y=cy; catom_array[atom].z=cz; catom_array[atom].material=unit_cell.atom[uca].mat; catom_array[atom].uc_id=uca; catom_array[atom].lh_category=unit_cell.atom[uca].hc+z*maxlh; catom_array[atom].uc_category=unit_cell.atom[uca].lc; catom_array[atom].scx=x; catom_array[atom].scy=y; catom_array[atom].scz=z; catom_array[atom].include=false; // assume no atoms until classification complete atom++; } } #endif } } } } // Check to see if actual and expected number of atoms agree, if not trim the excess if(atom!=num_atoms){ std::vector<cs::catom_t> tmp_catom_array(num_atoms); tmp_catom_array=catom_array; catom_array.resize(atom); for(int a=0;a<atom;a++){ catom_array[a]=tmp_catom_array[a]; } tmp_catom_array.resize(0); } // If z-height material selection is enabled then do so if(cs::SelectMaterialByZHeight==true){ // Check for interfacial roughness and call custom material assignment routine if(cs::interfacial_roughness==true) cs::roughness(catom_array); // Check for multilayer system and if required generate multilayers else if(cs::multilayers) cs::generate_multilayers(catom_array); // Otherwise perform normal assignement of materials else{ // determine z-bounds for materials std::vector<double> mat_min(mp::num_materials); std::vector<double> mat_max(mp::num_materials); std::vector<bool> mat_fill(mp::num_materials); // Unroll min, max and fill for performance for(int mat=0;mat<mp::num_materials;mat++){ mat_min[mat]=mp::material[mat].min*cs::system_dimensions[2]; mat_max[mat]=mp::material[mat].max*cs::system_dimensions[2]; // alloys generally are not defined by height, and so have max = 0.0 if(mat_max[mat]<0.0000001) mat_max[mat]=-0.1; mat_fill[mat]=mp::material[mat].fill; } // Assign materials to generated atoms for(unsigned int atom=0;atom<catom_array.size();atom++){ for(int mat=0;mat<mp::num_materials;mat++){ const double cz=catom_array[atom].z; if((cz>=mat_min[mat]) && (cz<mat_max[mat]) && (mat_fill[mat]==false)){ catom_array[atom].material=mat; catom_array[atom].include=true; } } } } // Delete unneeded atoms clear_atoms(catom_array); } // Check to see if any atoms have been generated if(atom==0){ terminaltextcolor(RED); std::cout << "Error - no atoms have been generated, increase system dimensions!" << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Error: No atoms have been generated. Increase system dimensions." << std::endl; err::vexit(); } // Now unselect all atoms by default for particle shape cutting for(unsigned int atom=0;atom<catom_array.size();atom++){ catom_array[atom].include=false; } return EXIT_SUCCESS; }
/// /// @brief Initialise Constrained Monte Carlo module /// /// Creates the rotation matices for the given angle and computes the /// Boltzmann factor for the given temperature. /// /// @return void /// void CMCMCinit(){ // Check for calling of function if(err::check==true) std::cout << "sim::CMCMCinit has been called" << std::endl; // Create rotational matrices for cmc cmc::mat_polar_rot_matrix(); cmc::atom_list.resize(mp::num_materials); // create list of matching materials for(int atom=0;atom<atoms::num_atoms;atom++){ int mat=atoms::type_array[atom]; cmc::atom_list[mat].push_back(atom); } // Check for rotational update if(sim::constraint_rotation==false || (sim::constraint_theta_changed==false && sim::constraint_phi_changed==false)){ // Output message showing constraint direction re-initialisation zlog << zTs() << "Initialising spins in all materials to new constraint directions." << std::endl; // Initialise all spins along the constraint direction(s). for(int atom =0;atom<atoms::num_atoms;atom++){ int imat=atoms::type_array[atom]; if(mp::material[imat].constrained==true){ double sx=sin(cmc::cmc_mat[imat].constraint_phi*M_PI/180.0)*cos(cmc::cmc_mat[imat].constraint_theta*M_PI/180.0); double sy=sin(cmc::cmc_mat[imat].constraint_phi*M_PI/180.0)*sin(cmc::cmc_mat[imat].constraint_theta*M_PI/180.0); double sz=cos(cmc::cmc_mat[imat].constraint_phi*M_PI/180.0); atoms::x_spin_array[atom]=sx; atoms::y_spin_array[atom]=sy; atoms::z_spin_array[atom]=sz; } } } else{ // Output message showing constraint direction re-initialisation zlog << zTs() << "Initialising spins in material " << cmc::active_material << " by rotation to new constraint direction (phi, theta) " << cmc::cmc_mat[cmc::active_material].constraint_phi << " , " << cmc::cmc_mat[cmc::active_material].constraint_theta << std::endl; // Rotate spins from old to new constraint direction // Determine angles to rotate spins by double theta_old = cmc::cmc_mat[cmc::active_material].constraint_theta; double theta_new = cmc::cmc_mat[cmc::active_material].constraint_theta; double phi_old = cmc::cmc_mat[cmc::active_material].constraint_phi; double phi_new = cmc::cmc_mat[cmc::active_material].constraint_phi; // note - sim::constraint_phi, sim::constraint_theta are already at new angle if(sim::constraint_theta_changed) theta_old = cmc::cmc_mat[cmc::active_material].constraint_theta - cmc::cmc_mat[cmc::active_material].constraint_theta_delta; if(sim::constraint_phi_changed) phi_old = cmc::cmc_mat[cmc::active_material].constraint_phi - cmc::cmc_mat[cmc::active_material].constraint_phi_delta; // Rotate all spins in active material from theta_old to theta = 0 (reference direction along x) cmc::rotate_material_spins_around_z_axis(-theta_old, cmc::active_material); // Rotate all spins in active material from phi_old to phi_new cmc::rotate_material_spins_around_x_axis(phi_new-phi_old, cmc::active_material); // Rotate all spins in active material from theta = 0 to theta = theta_new cmc::rotate_material_spins_around_z_axis(theta_new, cmc::active_material); // reset rotation flags sim::constraint_theta_changed = false; sim::constraint_phi_changed = false; } // disable thermal field calculation sim::hamiltonian_simulation_flags[3]=0; // set initialised flag to true cmc::is_initialised=true; return; }
void zLogTsInit(std::string tmp){ // Get program name and process ID std::string tmprev; int linelength = tmp.length(); // set character triggers const char* key="/"; /// Word identifier // copy characters after last / for(int i=linelength-1;i>=0;i--){ char c=tmp.at(i); if(c != *key){ tmprev.push_back(c); } else break; } //reverse read into program name linelength=tmprev.size(); for(int i=linelength-1;i>=0;i--){ char c=tmprev.at(i); zLogProgramName.push_back(c); } // Get hostname char loghostname [80]; #ifdef WIN_COMPILE DWORD sizelhn = sizeof ( loghostname ); int GHS=!GetComputerName(loghostname, &sizelhn); //GetComputerName returns true when retrieves hostname #else int GHS=gethostname(loghostname, 80); #endif terminaltextcolor(YELLOW); if(GHS!=0) std::cerr << "Warning: Unable to retrieve hostname for zlog file." << std::endl; terminaltextcolor(WHITE); zLogHostName = loghostname; // Now get process ID #ifdef WIN_COMPILE zLogPid = _getpid(); #else zLogPid = getpid(); #endif // Open log filename if(vmpi::my_rank==0) zlog.open("log"); // Mark as initialised; zLogInitialised=true; zlog << zTs() << "Logfile opened" << std::endl; //------------------------------------ // Determine current directory //------------------------------------ char directory [256]; #ifdef WIN_COMPILE _getcwd(directory, sizeof(directory)); #else getcwd(directory, sizeof(directory)); #endif // write system and version information zlog << zTs() << "Executable : " << vout::zLogProgramName << std::endl; zlog << zTs() << "Host name : " << vout::zLogHostName << ":" << std::endl; zlog << zTs() << "Directory : " << directory << std::endl; zlog << zTs() << "Process ID : " << vout::zLogPid << std::endl; zlog << zTs() << "Version : " << vinfo::version() << std::endl; zlog << zTs() << "Githash : " << vinfo::githash() << std::endl; return; }
//---------------------------------------------------------------------- // // Function to generate rough surfaces (optionally unique) between // multiple materials at the interface of min/max. // // A local height is defined which overrides the min/max values of // the extent of the material as defined in the material file. No // atoms are added or removed by the process, but this will override // structural effects such as core-shell systems. // // The roughness is generated by creating seed points with a random // radius with a flat distribution around the mean. Within this // radius a stepwise change in the local height is defined, again // Gaussian distributed with a mean step height of zero. A maximum // Height is specified which truncates outlying values. Typical // values of the maximum step height would be 1-5 monolayers. // // The seed points are used to generate a 2D array defining the local // height for any point in space. A loop over all atoms then reassigns // atoms to materials according to the local height, overriding the // materials set in the crsytal. // //------------------------------------------------------------------------ // void roughness(std::vector<cs::catom_t> & catom_array){ // Output instructuve message to log file zlog << zTs() << "Calculating interfacial roughness for generated system." << std::endl; // Construct a 2D array of height according to roughness resoution const double resolution=cs::interfacial_roughness_height_field_resolution; // Angstroms const unsigned int seed_density=cs::interfacial_roughness_seed_count; const double seed_radius=cs::interfacial_roughness_mean_seed_radius; const double seed_height_mean=cs::interfacial_roughness_mean_seed_height; const double seed_height_max=cs::interfacial_roughness_seed_height_max; const double seed_radius_variance=cs::interfacial_roughness_seed_radius_variance; // Declare array to store height field std::vector<std::vector<double> >height_field(0); // Calculate size of height_field array double nx = int(vmath::iceil(cs::system_dimensions[0]/resolution)); double ny = int(vmath::iceil(cs::system_dimensions[1]/resolution)); // Resize height_field array height_field.resize(nx); for(int i=0; i<nx; i++) height_field.at(i).resize(ny); // Generate seed points and radii std::vector<seed_point_t> seed_points(0); // Define local random generator for surface roughness MTRand rgrnd; // Initialise random number generator rgrnd.seed(cs::interfacial_roughness_random_seed); for(unsigned int p=0; p < seed_density ; p++){ // Generate random point coordinates double x=rgrnd()*cs::system_dimensions[0]; double y=rgrnd()*cs::system_dimensions[1]; // Generate random radius with flat profile r = r0 +/- variance*rnd() double r=seed_radius*(1.0+seed_radius_variance*(2.0*rgrnd()-1.0)); // Generate random height with gaussian profile double h=seed_height_mean*mtrandom::gaussianc(rgrnd); // Overwrite generated height if greater than maximum if(fabs(h)>seed_height_max) h=vmath::sign(h)*seed_height_max; // Check for type of roughness // Troughs if(cs::interfacial_roughness_type==-1) h = -1.0*fabs(h); // Peaks else if(cs::interfacial_roughness_type==1) h = fabs(h); // Save point characteristics to array seed_point_t tmp; tmp.x = x; tmp.y = y; tmp.radius = r; tmp.height = h; seed_points.push_back(tmp); } // Now apply seed points to generate local height field // Loop over all height field coordinates for(int ix = 0; ix < nx; ix++){ for(int iy = 0; iy < ny; iy++){ const double x = double(ix)*resolution; // real space coordinates const double y = double(iy)*resolution; // Loop over all seed points for(unsigned int p=0; p < seed_density ; p++){ double rx=x-seed_points.at(p).x; double ry=y-seed_points.at(p).y; // Check for point in range if(rx*rx+ry*ry <= seed_points.at(p).radius*seed_points.at(p).radius) height_field.at(ix).at(iy)=seed_points.at(p).height; } } } // Assign materials to generated atoms for(unsigned int atom=0;atom<catom_array.size();atom++){ // Determine height field coordinates const int hx = int(catom_array[atom].x/resolution); const int hy = int(catom_array[atom].y/resolution); // Loop over all materials and determine local height for(int mat=0;mat<mp::num_materials;mat++){ double min=create::internal::mp[mat].min*cs::system_dimensions[2]; double max=create::internal::mp[mat].max*cs::system_dimensions[2]; double local_height = height_field.at(hx).at(hy); bool fill = mp::material[mat].fill; // optionally specify a material specific height here -- not yet implemented //if(cs::interfacial_roughness_local_height_field==true){ //double local_height = height_field.at(mat).at(hx).at(hy); //} const int atom_uc_cat = catom_array[atom].uc_category; const int mat_uc_cat = create::internal::mp[mat].unit_cell_category; // Include atoms if within material height const double cz=catom_array[atom].z; if((cz>=min+local_height) && (cz<max+local_height) && (fill==false) && (atom_uc_cat == mat_uc_cat) ){ catom_array[atom].material=mat; catom_array[atom].include=true; } } } return; }
/// /// @brief Initialise Constrained Monte Carlo module /// /// Creates the rotation matices for the given angle and computes the /// Boltzmann factor for the given temperature. /// /// @return void /// void CMCinit(){ // Check for calling of function if(err::check==true) std::cout << "sim::CMCinit has been called" << std::endl; // Create rotational matrices for cmc cmc::polar_rot_matrix(sim::constraint_phi,sim::constraint_theta, cmc::polar_matrix, cmc::polar_matrix_tp, cmc::polar_vector); // Check for rotational update if((sim::constraint_rotation==false || (sim::constraint_theta_changed==false && sim::constraint_phi_changed==false)) && sim::checkpoint_loaded_flag==false){ // Output message showing constraint direction re-initialisation zlog << zTs() << "Initialising spins to new constraint direction (phi, theta) " << sim::constraint_phi << " , " << sim::constraint_theta << std::endl; // Initialise all spins along the constraint direction. double sx=sin(sim::constraint_phi*M_PI/180.0)*cos(sim::constraint_theta*M_PI/180.0); double sy=sin(sim::constraint_phi*M_PI/180.0)*sin(sim::constraint_theta*M_PI/180.0); double sz=cos(sim::constraint_phi*M_PI/180.0); for(int atom =0;atom<atoms::num_atoms;atom++){ atoms::x_spin_array[atom]=sx; atoms::y_spin_array[atom]=sy; atoms::z_spin_array[atom]=sz; } } // If the simulation is restarted from within the temperature loop, then the spin configurations must not be reinitialised else if(sim::checkpoint_loaded_flag==true){ zlog << zTs() << "Not re-initialising spins to constraint directions since still in temperature loop" << std::endl; } else{ // Output message showing constraint direction re-initialisation zlog << zTs() << "Initialising spins by rotation from last constraint direction to new constraint direction (phi, theta) " << sim::constraint_phi << " , " << sim::constraint_theta << std::endl; // Rotate spins from old to new constraint direction // Determine angles to rotate spins by double theta_old = sim::constraint_theta; double theta_new = sim::constraint_theta; double phi_old = sim::constraint_phi; double phi_new = sim::constraint_phi; // note - sim::constraint_phi, sim::constraint_theta are already at new angle if(sim::constraint_theta_changed) theta_old = sim::constraint_theta - sim::constraint_theta_delta; if(sim::constraint_phi_changed) phi_old = sim::constraint_phi - sim::constraint_phi_delta; // Rotate all spins from theta_old to theta = 0 (reference direction along x) cmc::rotate_spins_around_z_axis(-theta_old); // Rotate all spins from phi_old to phi_new cmc::rotate_spins_around_x_axis(phi_new-phi_old); // Rotate all spins from theta = 0 to theta = theta_new cmc::rotate_spins_around_z_axis(theta_new); // reset rotation flags sim::constraint_theta_changed = false; sim::constraint_phi_changed = false; } // disable thermal field calculation sim::hamiltonian_simulation_flags[3]=0; // set initialised flag to true cmc::is_initialised=true; return; }
/// @brief Cells output function /// /// @details Outputs formatted data snapshot for visualisation /// /// //------------------------------------------------------ /// // Atomistic coordinate configuration file for vampire /// //------------------------------------------------------ /// // Date: xx/xx/xxxx xx.xx.xx /// //------------------------------------------------------ /// Number of cells: $n_cells /// //------------------------------------------------------ /// Number of atom files: $n_files /// atoms-coords-00CPU0.cfg /// atoms-coords-00CPU1.cfg /// atoms-coords-00CPU2.cfg /// //------------------------------------------------------ /// Number of local cells: $n_loc_cells /// $material $category $x $y $z $species /// $material $category $x $y $z $species /// $material $category $x ... /// /// @section License /// Use of this code, either in source or compiled form, is subject to license from the authors. /// Copyright \htmlonly © \endhtmlonly Richard Evans, 2009-2011. All Rights Reserved. /// /// @section Information /// @author Richard Evans, [email protected] /// @version 1.0 /// @date 31/05/2011 /// /// @internal /// Created: 31/05/2011 /// Revision: --- ///===================================================================================== /// void legacy_cells_coords() { // wait for all processes vmpi::barrier(); // instantiate timer vutil::vtimer_t timer; // Set local output filename std::stringstream file_sstr; file_sstr << "cells-coords"; file_sstr << ".cfg"; std::string cfg_file = file_sstr.str(); const char *cfg_filec = cfg_file.c_str(); // start timer timer.start(); // Output masterfile header on root process if (vmpi::my_rank == 0) { zlog << zTs() << "Outputting cell coordinates to disk" << std::flush; // Declare and open output file std::ofstream cfg_file_ofstr; cfg_file_ofstr.open(cfg_filec); // Get system date time_t rawtime = time(NULL); struct tm *timeinfo = localtime(&rawtime); cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Cell coordinates configuration file for vampire" << std::endl; cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Date: " << asctime(timeinfo); cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Number of cells: " << cells::num_cells << std::endl; cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "#" << std::endl; cfg_file_ofstr << "#" << std::endl; cfg_file_ofstr << "#" << std::endl; cfg_file_ofstr << "#" << std::endl; cfg_file_ofstr << "#" << std::endl; cfg_file_ofstr << "#------------------------------------------------------" << std::endl; config::internal::total_output_cells = 0; for (int cell = 0; cell < cells::num_cells; cell++){ if (cells::num_atoms_in_cell_global[cell] > 0){ cfg_file_ofstr << cell << "\t" << cells::num_atoms_in_cell_global[cell] << "\t" << cells::pos_and_mom_array[4 * cell + 0] << "\t" << cells::pos_and_mom_array[4 * cell + 1] << "\t" << cells::pos_and_mom_array[4 * cell + 2] << std::endl; config::internal::total_output_cells++; } } cfg_file_ofstr.close(); } // stop the timer timer.stop(); const double data_size = double(config::internal::total_output_cells) * 2.0 * sizeof(int) * 3.0 * sizeof(double); const double io_time = timer.elapsed_time(); zlog << " of size " << data_size*1.0e-6 << " MB [ " << data_size*1.0e-9/timer.elapsed_time() << " GB/s in " << io_time << " s ]" << std::endl; // wait for all processes vmpi::barrier(); return; }
/// @brief Cell output function /// /// @details Outputs formatted data snapshot for visualisation /// /// #------------------------------------------------------ /// # Cell configuration file for vampire /// #------------------------------------------------------ /// # Date: xx/xx/xxxx xx.xx.xx /// #------------------------------------------------------ /// Number of cells: $n_cells /// System dimensions: $max_x $max_y $max_z /// Coordinates-file: $coord_file /// Time: $t /// Field: $H /// Temperature: $T /// Magnetisation: $mx $my $mz /// Number of Materials: $n_mat /// Material Properties 1: $mu_s $mmx $mmy $mmz $mm /// Material Properties 2: $mu_s $mmx $mmy $mmz ... /// #------------------------------------------------------ /// /// @section License /// Use of this code, either in source or compiled form, is subject to license from the authors. /// Copyright \htmlonly © \endhtmlonly Richard Evans, 2009-2011. All Rights Reserved. /// /// @section Information /// @author Richard Evans, [email protected] /// @version 1.0 /// @date 26/04/2013 /// /// @internal /// Created: 26/04/2013 /// Revision: --- ///===================================================================================== /// void legacy_cells() { // wait for all processes vmpi::barrier(); // instantiate timer vutil::vtimer_t timer; // Set local output filename std::stringstream file_sstr; file_sstr << "cells-"; file_sstr << std::setfill('0') << std::setw(8) << sim::output_cells_file_counter; file_sstr << ".cfg"; std::string cfg_file = file_sstr.str(); const char *cfg_filec = cfg_file.c_str(); #ifdef MPICF // if flag to print cells field is active, all cpus send cells field to root proc if(dipole::activated) dipole::send_cells_field(cells::cell_id_array, dipole::cells_field_array_x, dipole::cells_field_array_y, dipole::cells_field_array_z, cells::num_local_cells); #endif // start timer timer.start(); // Output masterfile header on root process if (vmpi::my_rank == 0) { zlog << zTs() << "Outputting cell configuration " << sim::output_cells_file_counter << " to disk" << std::flush; // Declare and open output file std::ofstream cfg_file_ofstr; cfg_file_ofstr.open(cfg_filec); // Get system date time_t rawtime = time(NULL); struct tm *timeinfo = localtime(&rawtime); cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Cell configuration file for vampire" << std::endl; cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Date: " << asctime(timeinfo); cfg_file_ofstr << "#------------------------------------------------------" << std::endl; cfg_file_ofstr << "# Number of spins: " << cells::num_cells << std::endl; cfg_file_ofstr << "# System dimensions:" << cs::system_dimensions[0] << "\t" << cs::system_dimensions[1] << "\t" << cs::system_dimensions[2] << std::endl; cfg_file_ofstr << "# Coordinates-file: cells-coord.cfg" << std::endl; cfg_file_ofstr << "# Time: " << double(sim::time) * mp::dt_SI << std::endl; cfg_file_ofstr << "# Field: " << sim::H_applied << std::endl; cfg_file_ofstr << "# Temperature: " << sim::temperature << std::endl; cfg_file_ofstr << "# Magnetisation: " << stats::system_magnetization.output_normalized_magnetization() << std::endl; cfg_file_ofstr << "#------------------------------------------------------" << std::endl; // Root process now outputs the cell magnetisations for (int cell = 0; cell < cells::num_cells; cell++){ if (cells::num_atoms_in_cell_global[cell] > 0){ cfg_file_ofstr << cells::mag_array_x[cell] << "\t" << cells::mag_array_y[cell] << "\t" << cells::mag_array_z[cell] << "\t"; if(dipole::activated) cfg_file_ofstr << dipole::cells_field_array_x[cell] << "\t" << dipole::cells_field_array_y[cell] << "\t" << dipole::cells_field_array_z[cell] << "\n"; else cfg_file_ofstr << "\n"; } } cfg_file_ofstr.close(); } // stop the timer timer.stop(); double data_size = double(config::internal::total_output_cells) * 3.0 * sizeof(double); if(dipole::activated) data_size = data_size * 2.0; const double io_time = timer.elapsed_time(); zlog << " of size " << data_size*1.0e-6 << " MB [ " << data_size*1.0e-9/timer.elapsed_time() << " GB/s in " << io_time << " s ]" << std::endl; sim::output_cells_file_counter++; // wait for all processes vmpi::barrier(); return; }
//------------------------------------------------------------------------------ // // Function to set the type of exchange used in the code from a string // processed from the unit cell file. Default is normalised isotropic // exchange where the values of the exchange are set from the material // file. // // Function returns the number of exchange interactions specified in the // unit cell file. // //------------------------------------------------------------------------------ unsigned int set_exchange_type(std::string exchange_type_string){ //---------------------------------------- // check for standard isotropic exchange //---------------------------------------- const std::string isotropic_str = "isotropic"; if(isotropic_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::isotropic; // unset normalization flag exchange::internal::use_material_exchange_constants = false; return 1; // number of exchange interactions } //---------------------------------------- // check for standard vectorial exchange //---------------------------------------- const std::string vectorial_str = "vectorial"; if(vectorial_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::vectorial; // unset normalization flag exchange::internal::use_material_exchange_constants = false; return 3; // number of exchange interactions } //---------------------------------------- // check for standard tensorial exchange //---------------------------------------- const std::string tensorial_str = "tensorial"; if(tensorial_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::tensorial; // unset normalization flag exchange::internal::use_material_exchange_constants = false; return 9; // number of exchange interactions } //----------------------------------------- // check for normalised isotropic exchange //----------------------------------------- const std::string norm_isotropic_str = "normalised-isotropic"; if(norm_isotropic_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::isotropic; // unset normalization flag exchange::internal::use_material_exchange_constants = true; return 1; // number of exchange interactions } //----------------------------------------- // check for normalised vectorial exchange //----------------------------------------- const std::string norm_vectorial_str = "normalised-vectorial"; if(norm_vectorial_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::vectorial; // unset normalization flag exchange::internal::use_material_exchange_constants = true; return 3; // number of exchange interactions } //----------------------------------------- // check for normalised tensorial exchange //----------------------------------------- const std::string norm_tensorial_str = "normalised-tensorial"; if(norm_tensorial_str == exchange_type_string){ // set exchange type exchange::internal::exchange_type = internal::tensorial; // unset normalization flag exchange::internal::use_material_exchange_constants = true; return 9; // number of exchange interactions } terminaltextcolor(RED); zlog << zTs() << "\nError: Unkown exchange type \"" << exchange_type_string << "\" in unit cell file. Exiting!" << std::endl; std::cerr << "\nError: Unkown exchange type \"" << exchange_type_string << "\" in unit cell file. Exiting!" << std::endl; terminaltextcolor(WHITE); // exit program err::vexit(); return 0; }
/// @brief Function to run one a single program /// /// @callgraph /// @callergraph /// /// @section License /// Use of this code, either in source or compiled form, is subject to license from the authors. /// Copyright \htmlonly © \endhtmlonly Richard Evans, 2009-2011. All Rights Reserved. /// /// @section Information /// @author Richard Evans, [email protected] /// @version 1.1 /// @date 09/03/2011 /// /// @return EXIT_SUCCESS /// /// @internal /// Created: 02/10/2008 /// Revision: 1.1 09/03/2011 ///===================================================================================== /// int run(){ // Check for calling of function if(err::check==true) std::cout << "sim::run has been called" << std::endl; // Initialise simulation data structures sim::initialize(mp::num_materials); anisotropy::initialize(atoms::num_atoms, atoms::type_array, mp::mu_s_array); // now seed generator mtrandom::grnd.seed(vmpi::parallel_rng_seed(mtrandom::integration_seed)); // Check for load spin configurations from checkpoint if(sim::load_checkpoint_flag) load_checkpoint(); { // Set up statistical data sets #ifdef MPICF int num_atoms_for_statistics = vmpi::num_core_atoms+vmpi::num_bdry_atoms; #else int num_atoms_for_statistics = atoms::num_atoms; #endif // unroll list of non-magnetic materials std::vector<bool> non_magnetic_materials_array(mp::num_materials, false); for(int m = 0; m < mp::num_materials; m++){ if( mp::material[m].non_magnetic == 2 ) non_magnetic_materials_array[m] = true; } stats::initialize(num_atoms_for_statistics, mp::num_materials, atoms::m_spin_array, atoms::type_array, atoms::category_array, non_magnetic_materials_array); } // Precalculate initial statistics stats::update(atoms::x_spin_array, atoms::y_spin_array, atoms::z_spin_array, atoms::m_spin_array); // initialise dipole field calculation dipole::initialize(cells::num_atoms_in_unit_cell, cells::num_cells, cells::num_local_cells, cells::macro_cell_size, cells::local_cell_array, cells::num_atoms_in_cell, cells::num_atoms_in_cell_global, // <---- cells::index_atoms_array, cells::volume_array, cells::pos_and_mom_array, cells::atom_in_cell_coords_array_x, cells::atom_in_cell_coords_array_y, cells::atom_in_cell_coords_array_z, atoms::type_array, cells::atom_cell_id_array, atoms::x_coord_array, atoms::y_coord_array, atoms::z_coord_array, atoms::num_atoms ); // Initialize GPU acceleration if enabled if(gpu::acceleration) gpu::initialize(); // For MPI version, calculate initialisation time if(vmpi::my_rank==0){ #ifdef MPICF std::cout << "Time for initialisation: " << MPI_Wtime()-vmpi::start_time << std::endl; zlog << zTs() << "Time for initialisation: " << MPI_Wtime()-vmpi::start_time << std::endl; vmpi::start_time=MPI_Wtime(); // reset timer #endif } // Set timer for runtime stopwatch_t stopwatch; stopwatch.start(); // Precondition spins at equilibration temperature sim::internal::monte_carlo_preconditioning(); // For MPI version, calculate initialisation time if(vmpi::my_rank==0){ std::cout << "Starting Simulation with Program "; zlog << zTs() << "Starting Simulation with Program "; } // Now set initial compute time #ifdef MPICF vmpi::ComputeTime=MPI_Wtime(); vmpi::WaitTime=MPI_Wtime(); vmpi::TotalComputeTime=0.0; vmpi::TotalWaitTime=0.0; #endif // Select program to run switch(sim::program){ case 0: if(vmpi::my_rank==0){ std::cout << "Benchmark..." << std::endl; zlog << "Benchmark..." << std::endl; } program::bmark(); break; case 1: if(vmpi::my_rank==0){ std::cout << "Time-Series..." << std::endl; zlog << "Time-Series..." << std::endl; } program::time_series(); break; case 2: if(vmpi::my_rank==0){ std::cout << "Hysteresis-Loop..." << std::endl; zlog << "Hysteresis-Loop..." << std::endl; } program::hysteresis(); break; case 3: if(vmpi::my_rank==0){ std::cout << "Static-Hysteresis-Loop..." << std::endl; zlog << "Static-Hysteresis-Loop..." << std::endl; } program::static_hysteresis(); break; case 4: if(vmpi::my_rank==0){ std::cout << "Curie-Temperature..." << std::endl; zlog << "Curie-Temperature..." << std::endl; } program::curie_temperature(); break; case 5: if(vmpi::my_rank==0){ std::cout << "Field-Cool..." << std::endl; zlog << "Field-Cool..." << std::endl; } program::field_cool(); break; case 6: if(vmpi::my_rank==0){ std::cout << "Temperature-Pulse..." << std::endl; zlog << "Temperature-Pulse..." << std::endl; } program::temperature_pulse(); break; case 7: if(vmpi::my_rank==0){ std::cout << "HAMR-Simulation..." << std::endl; zlog << "HAMR-Simulation..." << std::endl; } program::hamr(); break; case 8: if(vmpi::my_rank==0){ std::cout << "CMC-Anisotropy..." << std::endl; zlog << "CMC-Anisotropy..." << std::endl; } program::cmc_anisotropy(); break; case 9: if(vmpi::my_rank==0){ std::cout << "Hybrid-CMC..." << std::endl; zlog << "Hybrid-CMC..." << std::endl; } program::hybrid_cmc(); break; case 10: if(vmpi::my_rank==0){ std::cout << "Reverse-Hybrid-CMC..." << std::endl; zlog << "Reverse-Hybrid-CMC..." << std::endl; } program::reverse_hybrid_cmc(); break; case 11: if(vmpi::my_rank==0){ std::cout << "LaGrange-Multiplier..." << std::endl; zlog << "LaGrange-Multiplier..." << std::endl; } program::lagrange_multiplier(); break; case 12: if(vmpi::my_rank==0){ std::cout << "partial-hysteresis-loop..." << std::endl; zlog << "partial-hysteresis-loop..." << std::endl; } program::partial_hysteresis_loop(); break; case 13: if(vmpi::my_rank==0){ std::cout << "localised-temperature-pulse..." << std::endl; zlog << "localised-temperature-pulse..." << std::endl; } program::localised_temperature_pulse(); break; case 14: if(vmpi::my_rank==0){ std::cout << "effective-damping..." << std::endl; zlog << "effective-damping..." << std::endl; } program::effective_damping(); break; case 15: if(vmpi::my_rank==0){ std::cout << "fmr..." << std::endl; zlog << "fmr..." << std::endl; } program::fmr(); break; case 16: if(vmpi::my_rank==0){ std::cout << "localised-field-cool..." << std::endl; zlog << "localised-field-cool..." << std::endl; } program::local_field_cool(); break; case 50: if(vmpi::my_rank==0){ std::cout << "Diagnostic-Boltzmann..." << std::endl; zlog << "Diagnostic-Boltzmann..." << std::endl; } program::boltzmann_dist(); break; case 51: if(vmpi::my_rank==0){ std::cout << "Setting..." << std::endl; zlog << "Setting..." << std::endl; } program::setting_process(); break; default:{ std::cerr << "Unknown Internal Program ID "<< sim::program << " requested, exiting" << std::endl; zlog << "Unknown Internal Program ID "<< sim::program << " requested, exiting" << std::endl; exit (EXIT_FAILURE); } } std::cout << "Simulation run time [s]: " << stopwatch.elapsed_seconds() << std::endl; zlog << zTs() << "Simulation run time [s]: " << stopwatch.elapsed_seconds() << std::endl; //------------------------------------------------ // Output Monte Carlo statistics if applicable //------------------------------------------------ if(sim::integrator==1){ std::cout << "Monte Carlo statistics:" << std::endl; std::cout << "\tTotal moves: " << long(sim::mc_statistics_moves) << std::endl; std::cout << "\t" << ((sim::mc_statistics_moves - sim::mc_statistics_reject)/sim::mc_statistics_moves)*100.0 << "% Accepted" << std::endl; std::cout << "\t" << (sim::mc_statistics_reject/sim::mc_statistics_moves)*100.0 << "% Rejected" << std::endl; zlog << zTs() << "Monte Carlo statistics:" << std::endl; zlog << zTs() << "\tTotal moves: " << sim::mc_statistics_moves << std::endl; zlog << zTs() << "\t" << ((sim::mc_statistics_moves - sim::mc_statistics_reject)/sim::mc_statistics_moves)*100.0 << "% Accepted" << std::endl; zlog << zTs() << "\t" << (sim::mc_statistics_reject/sim::mc_statistics_moves)*100.0 << "% Rejected" << std::endl; } if(sim::integrator==3 || sim::integrator==4){ std::cout << "Constrained Monte Carlo statistics:" << std::endl; std::cout << "\tTotal moves: " << cmc::mc_total << std::endl; std::cout << "\t" << (cmc::mc_success/cmc::mc_total)*100.0 << "% Accepted" << std::endl; std::cout << "\t" << (cmc::energy_reject/cmc::mc_total)*100.0 << "% Rejected (Energy)" << std::endl; std::cout << "\t" << (cmc::sphere_reject/cmc::mc_total)*100.0 << "% Rejected (Sphere)" << std::endl; zlog << zTs() << "Constrained Monte Carlo statistics:" << std::endl; zlog << zTs() << "\tTotal moves: " << cmc::mc_total << std::endl; zlog << zTs() << "\t" << (cmc::mc_success/cmc::mc_total)*100.0 << "% Accepted" << std::endl; zlog << zTs() << "\t" << (cmc::energy_reject/cmc::mc_total)*100.0 << "% Rejected (Energy)" << std::endl; zlog << zTs() << "\t" << (cmc::sphere_reject/cmc::mc_total)*100.0 << "% Rejected (Sphere)" << std::endl; } //program::LLB_Boltzmann(); // De-initialize GPU if(gpu::acceleration) gpu::finalize(); // optionally save checkpoint file if(sim::save_checkpoint_flag && !sim::save_checkpoint_continuous_flag) save_checkpoint(); return EXIT_SUCCESS; }