예제 #1
0
   //--------------------------------------------------------------------------
   // Function to create a multilayer system replicating a standard stack
   // structure cs::num_multilayers times
   //
   //   |-----------------------|  1.0          |-----------------------| L2 M2
   //   |      Material 2       |               |-----------------------|
   //   |-----------------------|  0.6   x2     |                       | L2 M2
   //   |                       |        -->    |-----------------------| L1 M1
   //   |      Material 1       |               |-----------------------|
   //   |                       |               |                       | L1 M2
   //   |-----------------------|  0.0          |-----------------------|
   //
   // The multilayers code divides the total system height into n multiples
   // of the defined material heights.
   //--------------------------------------------------------------------------
   void generate_multilayers(std::vector<cs::catom_t>& catom_array){

      // Load number of multilayer repeats to temporary constant
      const int num_layers = cs::num_multilayers;

      // Determine fractional system height for each layer
      const double fractional_system_height = cs::system_dimensions[2]/double(num_layers);

      // Unroll min, max and fill for performance
      std::vector<double> mat_min(mp::num_materials);
      std::vector<double> mat_max(mp::num_materials);
      std::vector<bool> mat_fill(mp::num_materials);

      for(int mat=0;mat<mp::num_materials;mat++){
         mat_min[mat]=mp::material[mat].min;
         mat_max[mat]=mp::material[mat].max;
         // 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++){
         // loop over multilayers
         for(int multi=0; multi < num_layers; ++multi){
            const double multilayer_num = double(multi);
            for(int mat=0;mat<mp::num_materials;mat++){
               // determine mimimum and maximum heigh for this layer
               const double mat_min_z = (mat_min[mat] + multilayer_num)*fractional_system_height;
               const double mat_max_z = (mat_max[mat] + multilayer_num)*fractional_system_height;
               const double cz=catom_array[atom].z;
               // if in range then allocate to material
               if((cz>=mat_min_z) && (cz<mat_max_z) && (mat_fill[mat]==false)){
                  catom_array[atom].material=mat;
                  catom_array[atom].include=true;
                  // Optionally recategorize heigh magnetization by layer in multilayer
                  if(cs::multilayer_height_category) catom_array[atom].lh_category = multi;
               }
            }
         }
      }

      return;

   }
예제 #2
0
   void sphere(std::vector<double>& particle_origin, std::vector<cs::catom_t> & catom_array, const int grain){

   	// Set particle radius
   	double particle_radius_squared = (cs::particle_scale*0.5)*(cs::particle_scale*0.5);

   	// Loop over all atoms and mark atoms in sphere
   	const int num_atoms = catom_array.size();

      // determine order for core-shell particles
      std::list<core_radius_t> material_order(0);
      for(int mat=0;mat<mp::num_materials;mat++){
         core_radius_t tmp;
         tmp.mat=mat;
         tmp.radius=mp::material[mat].core_shell_size;
         material_order.push_back(tmp);
      }
      // sort by increasing radius
      material_order.sort(compare_radius);

      // Unroll min, max and fill for performance
      std::vector<double> mat_min(mp::num_materials);
      std::vector<double> mat_max(mp::num_materials);
      std::vector<double> mat_cssize(mp::num_materials);
      std::vector<int> uc_cat(mp::num_materials); // array of material -> unit cell material associations

      for(int mat=0;mat<mp::num_materials;mat++){
         mat_min[mat]=create::internal::mp[mat].min*cs::system_dimensions[2];
         mat_max[mat]=create::internal::mp[mat].max*cs::system_dimensions[2];
         mat_cssize[mat] = mp::material[mat].core_shell_size;
         // alloys generally are not defined by height, and so have max = 0.0
         if(mat_max[mat]<1.e-99) mat_max[mat]=-0.1;
         uc_cat[mat] = create::internal::mp[mat].unit_cell_category; // unit cell category of material
      }

    	for(int atom=0;atom<num_atoms;atom++){
   		double range_squared = (catom_array[atom].x-particle_origin[0])*(catom_array[atom].x-particle_origin[0]) +
   							 (catom_array[atom].y-particle_origin[1])*(catom_array[atom].y-particle_origin[1]) +
   							 (catom_array[atom].z-particle_origin[2])*(catom_array[atom].z-particle_origin[2]);
         const double cz=catom_array[atom].z;
         const int atom_uc_cat = catom_array[atom].uc_category;

   		if(mp::material[catom_array[atom].material].core_shell_size>0.0){
            // Iterate over materials
            for(std::list<core_radius_t>::iterator it = material_order.begin(); it !=  material_order.end(); it++){
               int mat = (it)->mat;
   				double my_radius = mat_cssize[mat];
   				double max_range = my_radius*my_radius*particle_radius_squared;
   				double maxz=mat_max[mat];
   				double minz=mat_min[mat];

   				// check for within core shell range
   				if(range_squared<=max_range){
   					if((cz>=minz) && (cz<maxz) && (atom_uc_cat == uc_cat[mat]) ){
   						catom_array[atom].include=true;
   						catom_array[atom].material=mat;
   						catom_array[atom].grain=grain;
   					}
   					// if set to clear atoms then remove atoms within radius
   					else if(cs::fill_core_shell==false){
   						catom_array[atom].include=false;
   					}
   				}
   			}
   		}
   		else if(range_squared<=particle_radius_squared) {
   			catom_array[atom].include=true;
   			catom_array[atom].grain=grain;
   		}
   	}

   	return;

   }
예제 #3
0
/* LUfactor -- gaussian elimination with scaled partial pivoting
-- Note: returns LU matrix which is A */
MAT	*LUfactor(MAT *A, PERM *pivot)
{
  unsigned int	i, j, m, n;
  unsigned int	k, k_max;
  int i_max;
  char MatrixTempBuffer[ 1000 ];
  MatrixReal	**A_v, *A_piv, *A_row;
  MatrixReal	max1, temp, tiny;
  VEC	*scale = VNULL;

  if ( A==(MAT *)NULL || pivot==(PERM *)NULL ){
    error(E_NULL,"LUfactor");
  }
  if ( pivot->size != A->m )
    error(E_SIZES,"LUfactor");
  m = A->m;	n = A->n;

  if( SET_VEC_SIZE( A->m ) <1000 )
    vec_get( &scale, (void *)MatrixTempBuffer, A->m );
  else
    scale = v_get( A->m );

  //MEM_STAT_REG(scale,TYPE_VEC);
  A_v = A->me;

  tiny = (MatrixReal)(10.0/HUGE_VAL);

  /* initialise pivot with identity permutation */
  for ( i=0; i<m; i++ )
    pivot->pe[i] = i;

  /* set scale parameters */
  for ( i=0; i<m; i++ )
  {
    max1 = 0.0;
    for ( j=0; j<n; j++ )
    {
      temp = (MatrixReal)fabs(A_v[i][j]);
      max1 = mat_max(max1,temp);
    }
    scale->ve[i] = max1;
  }

  /* main loop */
  k_max = mat_min(m,n)-1;
  for ( k=0; k<k_max; k++ )
  {
    /* find best pivot row */
    max1 = 0.0;	i_max = -1;
    for ( i=k; i<m; i++ )
      if ( fabs(scale->ve[i]) >= tiny*fabs(A_v[i][k]) )
      {
        temp = (MatrixReal)fabs(A_v[i][k])/scale->ve[i];
        if ( temp > max1 )
        { max1 = temp;	i_max = i;	}
      }

      /* if no pivot then ignore column k... */
      if ( i_max == -1 )
      {
        /* set pivot entry A[k][k] exactly to zero,
        rather than just "small" */
        A_v[k][k] = 0.0;
        continue;
      }

      /* do we pivot ? */
      if ( i_max != (int)k )	/* yes we do... */
      {
        px_transp(pivot,i_max,k);
        for ( j=0; j<n; j++ )
        {
          temp = A_v[i_max][j];
          A_v[i_max][j] = A_v[k][j];
          A_v[k][j] = temp;
        }
      }

      /* row operations */
      for ( i=k+1; i<m; i++ )	/* for each row do... */
      {	/* Note: divide by zero should never happen */
        temp = A_v[i][k] = A_v[i][k]/A_v[k][k];
        A_piv = &(A_v[k][k+1]);
        A_row = &(A_v[i][k+1]);
        if ( k+1 < n )
          __mltadd__(A_row,A_piv,-temp,(int)(n-(k+1)));
      }

  }

  if( scale != (VEC *)MatrixTempBuffer ) // память выделялась, надо освободить
    V_FREE(scale);

  return A;
}
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;
}