Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
   //-------------------------------------------------------------------------------
   // 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;
   }
Ejemplo n.º 3
0
//------------------------------------------------------------------------------------------------------
// 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;

}
Ejemplo n.º 4
0
   //---------------------------------------------------------------------------
   // 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;

   }
Ejemplo n.º 5
0
/// @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 &copy \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;
}
Ejemplo n.º 6
0
   /// 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);
   }
Ejemplo n.º 7
0
   //------------------------------------------------------------------------------
   //
   //    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;

   }
Ejemplo n.º 8
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;

}
Ejemplo n.º 9
0
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;

}
Ejemplo n.º 10
0
///
/// @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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 13
0
   //---------------------------------------------------------------------------
   // 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;

   }
Ejemplo n.º 14
0
	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;
	}
Ejemplo n.º 15
0
//------------------------------------------------------------------------------
//  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;

}
Ejemplo n.º 16
0
/// @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 &copy \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;
}