/** * @file interface_particles.cpp * @author Julian Iseringhausen * @date Mon Apr 18 12:56:48 2011 * * @brief VMG::InterfaceParticles * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_MPI #include #endif #include #include #include "base/helper.hpp" #include "base/index.hpp" #include "base/linked_cell_list.hpp" #include "base/vector.hpp" #include "comm/comm.hpp" #include "grid/grid.hpp" #include "grid/multigrid.hpp" #include "grid/tempgrid.hpp" #include "interface/interface_particles.hpp" #include "mg.hpp" using namespace VMG; void InterfaceParticles::ImportRightHandSide(Multigrid& multigrid) { Index index_global, index_local, index; Vector pos_rel, pos_abs, grid_val; Factory& factory = MG::GetFactory(); Comm& comm = *MG::GetComm(); const int& near_field_cells = factory.GetObjectStorageVal("PARTICLE_NEAR_FIELD_CELLS"); Grid& grid = multigrid(multigrid.GlobalMaxLevel()); Grid& particle_grid = comm.GetParticleGrid(); particle_grid.Clear(); /* * Distribute particles to their processes */ particles.clear(); comm.CommParticles(grid, particles); /* * Charge assignment on the grid */ std::list::iterator iter; #ifdef DEBUG_OUTPUT vmg_float particle_charges = 0.0; for (iter=particles.begin(); iter!=particles.end(); ++iter) particle_charges += iter->Charge(); particle_charges = MG::GetComm()->GlobalSumRoot(particle_charges); comm.PrintStringOnce("Particle list charge sum: %e", particle_charges); #endif for (iter=particles.begin(); iter!=particles.end(); ++iter) spl.SetSpline(particle_grid, *iter, near_field_cells); // Communicate charges over halo comm.CommFromGhosts(particle_grid); // Assign charge values to the right hand side for (index.X()=0; index.X()GlobalSum(charge_sum); comm.PrintStringOnce("Grid charge sum: %e", charge_sum); #endif } void InterfaceParticles::ExportSolution(Grid& grid) { Index index; vmg_float length; Vector dist_vec; #ifdef DEBUG_OUTPUT vmg_float e = 0.0; vmg_float e_long = 0.0; vmg_float e_self = 0.0; #endif Factory& factory = MG::GetFactory(); Comm& comm = *MG::GetComm(); /* * Get parameters and arrays */ const vmg_int& num_particles_local = factory.GetObjectStorageVal("PARTICLE_NUM_LOCAL"); const int& near_field_cells = factory.GetObjectStorageVal("PARTICLE_NEAR_FIELD_CELLS"); vmg_float* p = factory.GetObjectStorageArray("PARTICLE_POTENTIAL_ARRAY"); vmg_float* f = factory.GetObjectStorageArray("PARTICLE_FORCE_ARRAY"); const vmg_float r_cut = (near_field_cells+0.5) * grid.Extent().MeshWidth().Max(); /* * Initialize potential */ for (vmg_int i=0; i::iterator p_iter; for (p_iter=particles.begin(); p_iter!=particles.end(); ++p_iter) { // Interpolate long range part of potential p_iter->Pot() = 0.5 * (Helper::InterpolateTrilinear(p_iter->Pos(), particle_grid) - p_iter->Charge() * spl.GetAntiDerivativeZero()); #ifdef DEBUG_OUTPUT e_long += 0.5 * p_iter->Charge() * Helper::InterpolateTrilinear(p_iter->Pos(), particle_grid); e_self += 0.5 * p_iter->Charge() * p_iter->Charge() * spl.GetAntiDerivativeZero(); #endif } comm.CommAddPotential(particles); /* * Compute near field correction */ Particle::LinkedCellList lc(particles, near_field_cells, grid); Particle::LinkedCellList::iterator p1, p2; Grid::iterator iter; comm.CommLCListGhosts(grid, lc); for (iter=lc.Iterators().Local().Begin(); iter!=lc.Iterators().Local().End(); ++iter) for (p1=lc(*iter).begin(); p1!=lc(*iter).end(); ++p1) for (index.X()=-1*near_field_cells-1; index.X()<=near_field_cells+1; ++index.X()) for (index.Y()=-1*near_field_cells-1; index.Y()<=near_field_cells+1; ++index.Y()) for (index.Z()=-1*near_field_cells-1; index.Z()<=near_field_cells+1; ++index.Z()) for (p2=lc(*iter+index).begin(); p2!=lc(*iter+index).end(); ++p2) if (*p1 != *p2) { length = (p2->Pos() - p1->Pos()).Length(); //TODO Rewrite this equation more efficiently if (length < r_cut) p1->Pot() += 0.5 * p2->Charge() / length * (0.25*M_1_PI + spl.EvaluatePotential(length)); } comm.CommAddPotential(lc); #ifdef DEBUG_OUTPUT vmg_float* q = factory.GetObjectStorageArray("PARTICLE_CHARGE_ARRAY"); for (int i=0; i