int output_mag(std::ofstream& ofile){ // check calling of routine if error checking is activated if(err::check==true){std::cout << "grains::output_mag has been called" << std::endl;} // calculate grain magnetisations grains::mag(); if(vmpi::my_rank==0){ // check file stream is open if(!ofile.is_open()){ terminaltextcolor(RED); std::cerr << "Error - file stream is unopened for grains::output_mag(), exiting!" << std::endl; terminaltextcolor(WHITE); err::vexit(); } unsigned int id=0; // grain id (excluding grains with zero atoms) // calculate mag_m of each grain and normalised direction for(int grain=0;grain<grains::num_grains;grain++){ // check for grains with zero atoms if(grains::grain_size_array[grain]==0){ //std::cerr << "Warning Grain " << grain << " has no constituent atoms!" << std::endl; } else{ ofile << grain << "\t" << id << "\t" << grains::x_mag_array[grain] << "\t" << grains::y_mag_array[grain]; ofile << "\t" << grains::z_mag_array[grain] << "\t" << grains::mag_m_array[grain] << std::endl; id++; } } } return EXIT_SUCCESS; }
//------------------------------------------------------------------------------- // 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; }
//------------------------------------------------------------------------------------------------------ // 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; }
/// @brief Function to output timestamp to stream /// /// @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-2012. All Rights Reserved. /// /// @section Information /// @author Richard Evans, [email protected] /// @version 1.0 /// @date 19/04/2012 /// /// @return TS /// /// @internal /// Created: 19/04/2012 /// Revision: --- ///===================================================================================== /// std::string zTs(){ std::string NullString; NullString=""; if(vout::zLogInitialised==true){ std::ostringstream Ts; // varibale for time time_t seconds; // get current time seconds = time (NULL); struct tm * timeinfo; char logtime [80]; timeinfo = localtime ( &seconds ); // Format time string //strftime (logtime,80,"%Y-%m-%d %X ",timeinfo); strftime (logtime,80,"%d-%m-%Y [%X] ",timeinfo); Ts << logtime; // << vout::zLogProgramName << " [" << vout::zLogHostName << ":" << vout::zLogPid << ":"<< vmpi::my_rank << "] "; return Ts.str(); } else{ terminaltextcolor(RED); std::cerr << "Error! - zlog not initialised, exiting" << std::endl; // This can be recursive - vexit calls zTs() //err::vexit(); // Exit manually std::cerr << "Fatal error: Aborting program. See log file for details." << std::endl; terminaltextcolor(WHITE); exit(EXIT_FAILURE); } return NullString; }
/// Default vexit void vexit(){ // check calling of routine if error checking is activated if(err::check==true){ terminaltextcolor(RED); std::cout << "err::vexit has been called" << std::endl; terminaltextcolor(WHITE); } // Abort MPI processes for parallel execution #ifdef MPICF terminaltextcolor(RED); std::cerr << "Fatal error on rank: " << vmpi::my_rank << ": Aborting program." << std::endl; terminaltextcolor(WHITE); zlog << zTs() << "Fatal error on rank: " << vmpi::my_rank << ": 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 #endif // Print error message to screen and log zlog << zTs() << "Fatal error: Aborting program." << std::endl; terminaltextcolor(RED); std::cout << "Fatal error: Aborting program. See log file for details." << std::endl; terminaltextcolor(WHITE); // Now exit program disgracefully exit(EXIT_FAILURE); }
//------------------------------------------------------------------------------ // // 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; }
int set_properties(){ //======================================================================================================== /// Function to calculate number of atoms in each grain // /// Version 1.0 // /// R F Evans 15/07/2009 // //======================================================================================================== //---------------------------------------------------------- // check calling of routine if error checking is activated //---------------------------------------------------------- if(err::check==true){std::cout << "grains::set_properties has been called" << std::endl;} #ifdef MPICF const unsigned int num_local_atoms = vmpi::num_core_atoms+vmpi::num_bdry_atoms; #else const unsigned int num_local_atoms = atoms::num_atoms; #endif // resize and initialise grain arrays if(grains::num_grains > 0){ grains::grain_size_array.resize(grains::num_grains,0); grains::x_coord_array.resize(grains::num_grains,0.0); grains::y_coord_array.resize(grains::num_grains,0.0); grains::z_coord_array.resize(grains::num_grains,0.0); grains::x_mag_array.resize(grains::num_grains,0.0); grains::y_mag_array.resize(grains::num_grains,0.0); grains::z_mag_array.resize(grains::num_grains,0.0); grains::mag_m_array.resize(grains::num_grains,0.0); grains::sat_mag_array.resize(grains::num_grains,0.0); if(mp::num_materials>1){ grains::x_mat_mag_array.resize(grains::num_grains*mp::num_materials,0.0); grains::y_mat_mag_array.resize(grains::num_grains*mp::num_materials,0.0); grains::z_mat_mag_array.resize(grains::num_grains*mp::num_materials,0.0); grains::mat_mag_m_array.resize(grains::num_grains*mp::num_materials,0.0); grains::mat_sat_mag_array.resize(grains::num_grains*mp::num_materials,0.0); } } else{ terminaltextcolor(RED); std::cerr << "Warning - no grains detected!" << std::endl; terminaltextcolor(WHITE); } // loop over atoms to determine grain properties for(unsigned int atom=0;atom< num_local_atoms;atom++){ const int grain = atoms::grain_array[atom]; const int mat = atoms::type_array[atom]; // check grain is within allowable bounds if((grain>=0) && (grain<grains::num_grains)){ grains::grain_size_array[grain]+=1; grains::x_coord_array[grain]+=atoms::x_coord_array[atom]; grains::y_coord_array[grain]+=atoms::y_coord_array[atom]; grains::z_coord_array[grain]+=atoms::z_coord_array[atom]; grains::sat_mag_array[grain]+=mp::material[mat].mu_s_SI; if(mp::num_materials>1) grains::mat_sat_mag_array[grain*mp::num_materials+mat]+=mp::material[mat].mu_s_SI; } else{ terminaltextcolor(RED); std::cerr << "Error - atom " << atom << " belongs to grain " << grain << " which is greater than maximum number of grains "; std::cerr << grains::num_grains << ". Exiting" << std::endl; terminaltextcolor(WHITE); err::vexit(); } } // Reduce grain properties on all CPUs #ifdef MPICF //MPI::COMM_WORLD.Allreduce(&grains::grain_size_array[0], &grains::grain_size_array[0],grains::num_grains, MPI_INT,MPI_SUM); //MPI::COMM_WORLD.Allreduce(&grains::x_coord_array[0], &grains::x_coord_array[0],grains::num_grains, MPI_INT,MPI_SUM); //MPI::COMM_WORLD.Allreduce(&grains::y_coord_array[0], &grains::y_coord_array[0],grains::num_grains, MPI_INT,MPI_SUM); //MPI::COMM_WORLD.Allreduce(&grains::z_coord_array[0], &grains::z_coord_array[0],grains::num_grains, MPI_INT,MPI_SUM); //MPI::COMM_WORLD.Allreduce(&grains::sat_mag_array[0], &grains::sat_mag_array[0],grains::num_grains, MPI_INT,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::grain_size_array[0],grains::num_grains, MPI_INT,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::x_coord_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::y_coord_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::z_coord_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::sat_mag_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); if(mp::num_materials>1) MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::mat_sat_mag_array[0],grains::num_grains*mp::num_materials, MPI_DOUBLE,MPI_SUM); #endif //vinfo << "-------------------------------------------------------------------------------------------------------------------" << std::endl; //vinfo << "# Grain number\tnum atoms\tx\ty\tz\t" << std::endl; // Calculate mean grains coordinates for(int grain=0;grain<grains::num_grains;grain++){ // check for grains with zero atoms if(grains::grain_size_array[grain]==0){ //std::cerr << "Warning Grain " << grain << " has no constituent atoms!" << std::endl; } else{ grains::x_coord_array[grain]/=double(grains::grain_size_array[grain]); grains::y_coord_array[grain]/=double(grains::grain_size_array[grain]); grains::z_coord_array[grain]/=double(grains::grain_size_array[grain]); // output grain properties to vinfo //vinfo << grain << "\t" << grains::grain_size_array[grain] << "\t" << grains::x_coord_array[grain]; //vinfo << "\t" << grains::y_coord_array[grain] << "\t" << grains::z_coord_array[grain] << std::endl; } } return EXIT_SUCCESS; }
int mag(){ // check calling of routine if error checking is activated if(err::check==true){std::cout << "grains::mag has been called" << std::endl;} #ifdef MPICF const unsigned int num_local_atoms = vmpi::num_core_atoms+vmpi::num_bdry_atoms; #else const unsigned int num_local_atoms = atoms::num_atoms; #endif //initialise magnetisations for(int grain=0;grain<grains::num_grains;grain++){ grains::x_mag_array[grain]=0.0; grains::y_mag_array[grain]=0.0; grains::z_mag_array[grain]=0.0; grains::mag_m_array[grain]=0.0; if(mp::num_materials>1){ // loop over materials for(int mat=0;mat<mp::num_materials;mat++){ grains::x_mat_mag_array[grain*mp::num_materials+mat]=0.0; grains::y_mat_mag_array[grain*mp::num_materials+mat]=0.0; grains::z_mat_mag_array[grain*mp::num_materials+mat]=0.0; grains::mat_mag_m_array[grain*mp::num_materials+mat]=0.0; } } } // function to calculate grain magnetisations for(unsigned int atom=0;atom< num_local_atoms;atom++){ const int grain = atoms::grain_array[atom]; const int mat = atoms::type_array[atom]; // check grain is within allowable bounds if((grain>=0) && (grain<grains::num_grains)){ grains::x_mag_array[grain]+=(atoms::x_spin_array[atom]*mp::material[mat].mu_s_SI); grains::y_mag_array[grain]+=(atoms::y_spin_array[atom]*mp::material[mat].mu_s_SI); grains::z_mag_array[grain]+=(atoms::z_spin_array[atom]*mp::material[mat].mu_s_SI); if(mp::num_materials>1){ grains::x_mat_mag_array[grain*mp::num_materials+mat]+=(atoms::x_spin_array[atom]*mp::material[mat].mu_s_SI); grains::y_mat_mag_array[grain*mp::num_materials+mat]+=(atoms::y_spin_array[atom]*mp::material[mat].mu_s_SI); grains::z_mat_mag_array[grain*mp::num_materials+mat]+=(atoms::z_spin_array[atom]*mp::material[mat].mu_s_SI); } } else{ terminaltextcolor(RED); std::cerr << "Error - atom " << atom << " belongs to grain " << grain << " which is greater than maximum number of grains "; std::cerr << grains::num_grains << ". Exiting" << std::endl; terminaltextcolor(WHITE); err::vexit(); } } // Reduce grain properties on all CPUs #ifdef MPICF MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::x_mag_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::y_mag_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::z_mag_array[0],grains::num_grains, MPI_DOUBLE,MPI_SUM); if(mp::num_materials>1) MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::x_mat_mag_array[0],grains::num_grains*mp::num_materials, MPI_DOUBLE,MPI_SUM); if(mp::num_materials>1) MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::y_mat_mag_array[0],grains::num_grains*mp::num_materials, MPI_DOUBLE,MPI_SUM); if(mp::num_materials>1) MPI::COMM_WORLD.Allreduce(MPI_IN_PLACE, &grains::z_mat_mag_array[0],grains::num_grains*mp::num_materials, MPI_DOUBLE,MPI_SUM); #endif // calculate mag_m of each grain and normalised direction for(int grain=0;grain<grains::num_grains;grain++){ // check for grains with zero atoms if(grains::grain_size_array[grain]==0){ //std::cerr << "Warning Grain " << grain << " has no constituent atoms!" << std::endl; } else{ double norm = 1.0/grains::sat_mag_array[grain]; double mx = grains::x_mag_array[grain]*norm; double my = grains::y_mag_array[grain]*norm; double mz = grains::z_mag_array[grain]*norm; grains::mag_m_array[grain] = sqrt(mx*mx+my*my+mz*mz); // Normalise to unit magnetisation grains::x_mag_array[grain]*=norm; grains::y_mag_array[grain]*=norm; grains::z_mag_array[grain]*=norm; // loop over all materials and normalise if(mp::num_materials>1){ for(int mat=0;mat<mp::num_materials;mat++){ const unsigned int idx=grain*mp::num_materials+mat; const double immm = grains::mat_sat_mag_array[idx] < 1.e-200 ? 1.0 : 1.0/grains::mat_sat_mag_array[idx]; double mx = grains::x_mat_mag_array[idx]*immm; double my = grains::y_mat_mag_array[idx]*immm; double mz = grains::z_mat_mag_array[idx]*immm; grains::mat_mag_m_array[idx] = sqrt(mx*mx+my*my+mz*mz); // Normalise to unit magnetisation grains::x_mat_mag_array[idx]*=immm; grains::y_mat_mag_array[idx]*=immm; grains::z_mat_mag_array[idx]*=immm; } } } } return EXIT_SUCCESS; }
/// /// @brief Runs the Constrained Monte Carlo algorithm /// /// Chooses nspins random spin pairs from the spin system and attempts a /// Constrained Monte Carlo move on each pair, accepting for either lower /// energy or with a Boltzmann thermal weighting. /// /// @return void /// int ConstrainedMonteCarloMonteCarlo(){ // Check for calling of function if(err::check==true) std::cout << "sim::ConstrainedMonteCarlo has been called" << std::endl; // check for cmc initialisation if(cmc::is_initialised==false) CMCMCinit(); int atom_number1; int atom_number2; int imat1; int imat2; double delta_energy1; double delta_energy2; double delta_energy21; double Eold; double Enew; std::valarray<double> spin1_initial(3); std::valarray<double> spin1_final(3); double spin2_initial[3]; double spin2_final[3]; double spin1_init_mvd[3]; double spin1_fin_mvd[3]; double spin2_init_mvd[3]; double spin2_fin_mvd[3]; double M_other[3]; double Mz_old; double Mz_new; double sqrt_ran; double probability; // Material dependent temperature rescaling std::vector<double> rescaled_material_kBTBohr(mp::num_materials); std::vector<double> sigma_array(mp::num_materials); // range for tuned gaussian random move for(int m=0; m<mp::num_materials; ++m){ double alpha = mp::material[m].temperature_rescaling_alpha; double Tc = mp::material[m].temperature_rescaling_Tc; double rescaled_temperature = sim::temperature < Tc ? Tc*pow(sim::temperature/Tc,alpha) : sim::temperature; rescaled_material_kBTBohr[m] = 9.27400915e-24/(rescaled_temperature*1.3806503e-23); sigma_array[m] = pow(1.0/rescaled_material_kBTBohr[m],0.2)*0.08; } const int AtomExchangeType=atoms::exchange_type; // Cast as constant and pass to energy calculation for speed // save initial magnetisations for(int mat=0;mat<mp::num_materials;mat++){ cmc::cmc_mat[mat].M_other[0] = 0.0; cmc::cmc_mat[mat].M_other[1] = 0.0; cmc::cmc_mat[mat].M_other[2] = 0.0; } for(int atom=0;atom<atoms::num_atoms;atom++){ int mat=atoms::type_array[atom]; cmc::cmc_mat[mat].M_other[0] += atoms::x_spin_array[atom]; //multiplied by polar_vector below cmc::cmc_mat[mat].M_other[1] += atoms::y_spin_array[atom]; cmc::cmc_mat[mat].M_other[2] += atoms::z_spin_array[atom]; } // make a sequence of Monte Carlo moves for (int mcs=0;mcs<atoms::num_atoms;mcs++){ // Randomly select spin number 1 atom_number1 = int(mtrandom::grnd()*atoms::num_atoms); imat1=atoms::type_array[atom_number1]; sim::mc_delta_angle=sigma_array[imat1]; // check for constrained or unconstrained if(mp::material[imat1].constrained==false){ // normal MC // Save old spin position spin1_initial[0] = atoms::x_spin_array[atom_number1]; spin1_initial[1] = atoms::y_spin_array[atom_number1]; spin1_initial[2] = atoms::z_spin_array[atom_number1]; // Make Monte Carlo move sim::mc_move(spin1_initial, spin1_final); // Calculate current energy Eold = sim::calculate_spin_energy(atom_number1, AtomExchangeType); // Copy new spin position atoms::x_spin_array[atom_number1] = spin1_final[0]; atoms::y_spin_array[atom_number1] = spin1_final[1]; atoms::z_spin_array[atom_number1] = spin1_final[2]; // Calculate new energy Enew = sim::calculate_spin_energy(atom_number1, AtomExchangeType); // Calculate difference in Joules/mu_B delta_energy1 = (Enew-Eold)*mp::material[imat1].mu_s_SI*1.07828231e23; //1/9.27400915e-24 // Check for lower energy state and accept unconditionally if(delta_energy1<0){ cmc::mc_success += 1.0; } // Otherwise evaluate probability for move else{ if(exp(-delta_energy1*rescaled_material_kBTBohr[imat1]) >= mtrandom::grnd()){ cmc::mc_success += 1.0; } // If rejected reset spin coordinates and continue else{ atoms::x_spin_array[atom_number1] = spin1_initial[0]; atoms::y_spin_array[atom_number1] = spin1_initial[1]; atoms::z_spin_array[atom_number1] = spin1_initial[2]; cmc::energy_reject += 1.0; } } } else{ // constrained MC move const int imat=imat1; // Save initial Spin 1 spin1_initial[0] = atoms::x_spin_array[atom_number1]; spin1_initial[1] = atoms::y_spin_array[atom_number1]; spin1_initial[2] = atoms::z_spin_array[atom_number1]; //spin1_init_mvd = matmul(polar_matrix, spin1_initial) spin1_init_mvd[0]=cmc::cmc_mat[imat].ppolar_matrix[0][0]*spin1_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[0][1]*spin1_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[0][2]*spin1_initial[2]; spin1_init_mvd[1]=cmc::cmc_mat[imat].ppolar_matrix[1][0]*spin1_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[1][1]*spin1_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[1][2]*spin1_initial[2]; spin1_init_mvd[2]=cmc::cmc_mat[imat].ppolar_matrix[2][0]*spin1_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[2][1]*spin1_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[2][2]*spin1_initial[2]; // Make Monte Carlo move sim::mc_move(spin1_initial, spin1_final); //spin1_fin_mvd = matmul(polar_matrix, spin1_final) spin1_fin_mvd[0]=cmc::cmc_mat[imat].ppolar_matrix[0][0]*spin1_final[0]+cmc::cmc_mat[imat].ppolar_matrix[0][1]*spin1_final[1]+cmc::cmc_mat[imat].ppolar_matrix[0][2]*spin1_final[2]; spin1_fin_mvd[1]=cmc::cmc_mat[imat].ppolar_matrix[1][0]*spin1_final[0]+cmc::cmc_mat[imat].ppolar_matrix[1][1]*spin1_final[1]+cmc::cmc_mat[imat].ppolar_matrix[1][2]*spin1_final[2]; spin1_fin_mvd[2]=cmc::cmc_mat[imat].ppolar_matrix[2][0]*spin1_final[0]+cmc::cmc_mat[imat].ppolar_matrix[2][1]*spin1_final[1]+cmc::cmc_mat[imat].ppolar_matrix[2][2]*spin1_final[2]; // Calculate current energy Eold = sim::calculate_spin_energy(atom_number1, AtomExchangeType); // Copy new spin position (provisionally accept move) atoms::x_spin_array[atom_number1] = spin1_final[0]; atoms::y_spin_array[atom_number1] = spin1_final[1]; atoms::z_spin_array[atom_number1] = spin1_final[2]; // Calculate new energy Enew = sim::calculate_spin_energy(atom_number1, AtomExchangeType); // Calculate difference in Joules/mu_B delta_energy1 = (Enew-Eold)*mp::material[imat1].mu_s_SI*1.07828231e23; //1/9.27400915e-24 // Compute second move // Randomly select spin number 2 (i/=j) of same material type atom_number2 = cmc::atom_list[imat1][int(mtrandom::grnd()*cmc::atom_list[imat1].size())]; imat2=atoms::type_array[atom_number2]; if(imat1!=imat2){ terminaltextcolor(RED); std::cerr << "Error in MC/CMC integration! - atoms pairs are not from same material!" << std::endl; terminaltextcolor(WHITE); err::vexit(); } // Save initial Spin 2 spin2_initial[0] = atoms::x_spin_array[atom_number2]; spin2_initial[1] = atoms::y_spin_array[atom_number2]; spin2_initial[2] = atoms::z_spin_array[atom_number2]; //spin2_init_mvd = matmul(polar_matrix, spin2_initial) spin2_init_mvd[0]=cmc::cmc_mat[imat].ppolar_matrix[0][0]*spin2_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[0][1]*spin2_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[0][2]*spin2_initial[2]; spin2_init_mvd[1]=cmc::cmc_mat[imat].ppolar_matrix[1][0]*spin2_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[1][1]*spin2_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[1][2]*spin2_initial[2]; spin2_init_mvd[2]=cmc::cmc_mat[imat].ppolar_matrix[2][0]*spin2_initial[0]+cmc::cmc_mat[imat].ppolar_matrix[2][1]*spin2_initial[1]+cmc::cmc_mat[imat].ppolar_matrix[2][2]*spin2_initial[2]; // Calculate new spin based on constraint Mx=My=0 spin2_fin_mvd[0] = spin1_init_mvd[0]+spin2_init_mvd[0]-spin1_fin_mvd[0]; spin2_fin_mvd[1] = spin1_init_mvd[1]+spin2_init_mvd[1]-spin1_fin_mvd[1]; if(((spin2_fin_mvd[0]*spin2_fin_mvd[0]+spin2_fin_mvd[1]*spin2_fin_mvd[1])<1.0) && (atom_number1 != atom_number2)){ spin2_fin_mvd[2] = vmath::sign(spin2_init_mvd[2])*sqrt(1.0-spin2_fin_mvd[0]*spin2_fin_mvd[0] - spin2_fin_mvd[1]*spin2_fin_mvd[1]); //spin2_final = matmul(polar_matrix_tp, spin2_fin_mvd) spin2_final[0]=cmc::cmc_mat[imat].ppolar_matrix_tp[0][0]*spin2_fin_mvd[0]+cmc::cmc_mat[imat].ppolar_matrix_tp[0][1]*spin2_fin_mvd[1]+cmc::cmc_mat[imat].ppolar_matrix_tp[0][2]*spin2_fin_mvd[2]; spin2_final[1]=cmc::cmc_mat[imat].ppolar_matrix_tp[1][0]*spin2_fin_mvd[0]+cmc::cmc_mat[imat].ppolar_matrix_tp[1][1]*spin2_fin_mvd[1]+cmc::cmc_mat[imat].ppolar_matrix_tp[1][2]*spin2_fin_mvd[2]; spin2_final[2]=cmc::cmc_mat[imat].ppolar_matrix_tp[2][0]*spin2_fin_mvd[0]+cmc::cmc_mat[imat].ppolar_matrix_tp[2][1]*spin2_fin_mvd[1]+cmc::cmc_mat[imat].ppolar_matrix_tp[2][2]*spin2_fin_mvd[2]; //Calculate Energy Difference 2 // Calculate current energy Eold = sim::calculate_spin_energy(atom_number2, AtomExchangeType); // Copy new spin position (provisionally accept move) atoms::x_spin_array[atom_number2] = spin2_final[0]; atoms::y_spin_array[atom_number2] = spin2_final[1]; atoms::z_spin_array[atom_number2] = spin2_final[2]; // Calculate new energy Enew = sim::calculate_spin_energy(atom_number2, AtomExchangeType); // Calculate difference in Joules/mu_B delta_energy2 = (Enew-Eold)*mp::material[imat2].mu_s_SI*1.07828231e23; //1/9.27400915e-24 // Calculate Delta E for both spins delta_energy21 = delta_energy1*rescaled_material_kBTBohr[imat1] + delta_energy2*rescaled_material_kBTBohr[imat2]; // Compute Mz_other, Mz, Mz' Mz_old = cmc::cmc_mat[imat].M_other[0]*cmc::cmc_mat[imat].ppolar_vector[0] + cmc::cmc_mat[imat].M_other[1]*cmc::cmc_mat[imat].ppolar_vector[1] + cmc::cmc_mat[imat].M_other[2]*cmc::cmc_mat[imat].ppolar_vector[2]; Mz_new = (cmc::cmc_mat[imat].M_other[0] + spin1_final[0] + spin2_final[0]- spin1_initial[0] - spin2_initial[0])*cmc::cmc_mat[imat].ppolar_vector[0] + (cmc::cmc_mat[imat].M_other[1] + spin1_final[1] + spin2_final[1]- spin1_initial[1] - spin2_initial[1])*cmc::cmc_mat[imat].ppolar_vector[1] + (cmc::cmc_mat[imat].M_other[2] + spin1_final[2] + spin2_final[2]- spin1_initial[2] - spin2_initial[2])*cmc::cmc_mat[imat].ppolar_vector[2]; // Check for lower energy state and accept unconditionally //if((delta_energy21<0.0) && (Mz_new>=0.0) ) continue; // Otherwise evaluate probability for move //else{ // If move is favorable then accept probability = exp(-delta_energy21)*((Mz_new/Mz_old)*(Mz_new/Mz_old))*std::fabs(spin2_init_mvd[2]/spin2_fin_mvd[2]); if((probability>=mtrandom::grnd()) && (Mz_new>=0.0) ){ cmc::cmc_mat[imat].M_other[0] = cmc::cmc_mat[imat].M_other[0] + spin1_final[0] + spin2_final[0] - spin1_initial[0] - spin2_initial[0]; cmc::cmc_mat[imat].M_other[1] = cmc::cmc_mat[imat].M_other[1] + spin1_final[1] + spin2_final[1] - spin1_initial[1] - spin2_initial[1]; cmc::cmc_mat[imat].M_other[2] = cmc::cmc_mat[imat].M_other[2] + spin1_final[2] + spin2_final[2] - spin1_initial[2] - spin2_initial[2]; cmc::mc_success += 1.0; } //if both p1 and p2 not allowed then else{ // reset spin positions atoms::x_spin_array[atom_number1] = spin1_initial[0]; atoms::y_spin_array[atom_number1] = spin1_initial[1]; atoms::z_spin_array[atom_number1] = spin1_initial[2]; atoms::x_spin_array[atom_number2] = spin2_initial[0]; atoms::y_spin_array[atom_number2] = spin2_initial[1]; atoms::z_spin_array[atom_number2] = spin2_initial[2]; cmc::energy_reject += 1.0; } //} } // if s2 not on unit sphere else{ atoms::x_spin_array[atom_number1] = spin1_initial[0]; atoms::y_spin_array[atom_number1] = spin1_initial[1]; atoms::z_spin_array[atom_number1] = spin1_initial[2]; cmc::sphere_reject+=1.0; } } // end of cmc move cmc::mc_total += 1.0; } // end of mc loop 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; }
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; }
//--------------------------------------------------------------------------- // Function to process input file parameters for unitcell module //--------------------------------------------------------------------------- bool match_input_parameter(std::string const key, std::string const word, std::string const value, std::string const unit, int const line){ // Check for first prefix std::string prefix="unit-cell"; std::string test = ""; // Check for second prefix prefix="material"; if(key == prefix){ //------------------------------------------------------------------- // Get unit cell filename //------------------------------------------------------------------- test="unit-cell-file"; if(word==test){ std::string ucffile=value; // strip quotes ucffile.erase(std::remove(ucffile.begin(), ucffile.end(), '\"'), ucffile.end()); test=""; // if filename not blank set ucf file name if(ucffile!=test){ //std::cout << matfile << std::endl; uc::internal::unit_cell_filename=ucffile; return true; } else{ terminaltextcolor(RED); std::cerr << "Error - empty filename in control statement \'material:" << word << "\' on line " << line << " of input file" << std::endl; terminaltextcolor(WHITE); return false; } } } // Check for third prefix prefix="create"; if(key == prefix){ //-------------------------------------------------------------------- test="crystal-structure"; if(word==test){ // Strip quotes std::string cs=value; cs.erase(std::remove(cs.begin(), cs.end(), '\"'), cs.end()); uc::internal::crystal_structure=cs; return true; } } // Check for final prefix prefix="dimensions"; if(key == prefix){ test="unit-cell-size"; if(word==test){ double a=atof(value.c_str()); vin::check_for_valid_value(a, word, line, prefix, unit, "length", 0.1, 1.0e7,"input","0.1 Angstroms - 1 millimetre"); uc::internal::unit_cell_size_x=a; uc::internal::unit_cell_size_y=a; uc::internal::unit_cell_size_z=a; return true; } //-------------------------------------------------------------------- test="unit-cell-size-x"; if(word==test){ double ax=atof(value.c_str()); vin::check_for_valid_value(ax, word, line, prefix, unit, "length", 0.1, 1.0e7,"input","0.1 Angstroms - 1 millimetre"); uc::internal::unit_cell_size_x=ax; return true; } //-------------------------------------------------------------------- test="unit-cell-size-y"; if(word==test){ double ay=atof(value.c_str()); vin::check_for_valid_value(ay, word, line, prefix, unit, "length", 0.1, 1.0e7,"input","0.1 Angstroms - 1 millimetre"); uc::internal::unit_cell_size_y=ay; return true; } //-------------------------------------------------------------------- test="unit-cell-size-z"; if(word==test){ double az=atof(value.c_str()); vin::check_for_valid_value(az, word, line, prefix, unit, "length", 0.1, 1.0e7,"input","0.1 Angstroms - 1 millimetre"); uc::internal::unit_cell_size_z=az; return true; } } // add prefix string prefix="exchange"; if(key == prefix){ //-------------------------------------------------------------------- test="interaction-range"; if(word==test){ double ir=atof(value.c_str()); // Test for valid range vin::check_for_valid_value(ir, word, line, prefix, unit, "none", 1.0, 1000.0,"input","1.0 - 1000.0 nearest neighbour distances"); uc::internal::exchange_interaction_range = ir; return true; } //-------------------------------------------------------------------- test="decay-length"; if(word==test){ double dl=atof(value.c_str()); // Test for valid range vin::check_for_valid_value(dl, word, line, prefix, unit, "length", 0.1, 100.0,"input","1.0 - 100.0 Angstroms"); uc::internal::exchange_decay = dl; return true; } //-------------------------------------------------------------------- test="function"; if(word==test){ test="nearest-neighbour"; if(value==test){ uc::internal::exchange_function = uc::internal::nearest_neighbour; return true; } test="exponential"; if(value==test){ uc::internal::exchange_function = uc::internal::exponential; return true; } else{ terminaltextcolor(RED); std::cerr << "Error - value for \'exchange:" << word << "\' must be one of:" << std::endl; std::cerr << "\t\"nearest-neighbour\"" << std::endl; std::cerr << "\t\"exponential\"" << std::endl; terminaltextcolor(WHITE); err::vexit(); } } } //-------------------------------------------------------------------- // Keyword not found //-------------------------------------------------------------------- return false; }
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 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; }
/// @brief Wrapper function to call MPI parallel integrators /// /// @callgraph /// @callergraph /// /// @details Calls parallel integrators based on sim::integrator /// /// @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 07/03/2011 /// /// @return EXIT_SUCCESS /// /// @internal /// Created: 07/03/2011 /// Revision: --- ///===================================================================================== /// int integrate_mpi(uint64_t n_steps){ // Check for calling of function if(err::check==true) std::cout << "sim::integrate_mpi has been called" << std::endl; // Case statement to call integrator switch(sim::integrator){ case 0: // LLG Heun for(uint64_t ti=0;ti<n_steps;ti++){ #ifdef MPICF // Select CUDA version if supported #ifdef CUDA //sim::LLG_Heun_cuda_mpi(); #else sim::LLG_Heun_mpi(); #endif #endif // increment time increment_time(); } break; case 1: // Montecarlo for(uint64_t ti=0;ti<n_steps;ti++){ terminaltextcolor(RED); std::cerr << "Error - Monte Carlo Integrator unavailable for parallel execution" << std::endl; terminaltextcolor(WHITE); err::vexit(); // increment time increment_time(); } break; case 2: // LLG Midpoint for(uint64_t ti=0;ti<n_steps;ti++){ #ifdef MPICF // Select CUDA version if supported #ifdef CUDA //sim::LLG_Midpoint_cuda_mpi(); #else sim::LLG_Midpoint_mpi(); #endif #endif // increment time increment_time(); } break; case 3: // Constrained Monte Carlo for(uint64_t ti=0;ti<n_steps;ti++){ terminaltextcolor(RED); std::cerr << "Error - Constrained Monte Carlo Integrator unavailable for parallel execution" << std::endl; terminaltextcolor(WHITE); err::vexit(); // increment time increment_time(); } break; default:{ terminaltextcolor(RED); std::cerr << "Unknown integrator type "<< sim::integrator << " requested, exiting" << std::endl; terminaltextcolor(WHITE); exit (EXIT_FAILURE); } } return EXIT_SUCCESS; }