void MultiColvarBase::setupLinkCells(){ if( !linkcells.enabled() ) return ; unsigned iblock, jblock; if( usespecies ){ iblock=0; } else if( current_atoms.size()<4 ){ iblock=1; } else { plumed_error(); } // Count number of currently active atoms unsigned nactive_atoms=0; for(unsigned i=0;i<ablocks[iblock].size();++i){ if( isCurrentlyActive( ablocks[iblock][i] ) ) nactive_atoms++; } std::vector<Vector> ltmp_pos( nactive_atoms ); std::vector<unsigned> ltmp_ind( nactive_atoms ); nactive_atoms=0; if( usespecies ){ ltmp_pos.resize( ablocks[0].size() ); ltmp_ind.resize( ablocks[0].size() ); for(unsigned i=0;i<ablocks[0].size();++i){ if( !isCurrentlyActive( ablocks[0][i] ) ) continue; ltmp_ind[nactive_atoms]=ablocks[0][i]; ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] ); nactive_atoms++; } } else { ltmp_pos.resize( ablocks[1].size() ); ltmp_ind.resize( ablocks[1].size() ); for(unsigned i=0;i<ablocks[1].size();++i){ if( !isCurrentlyActive( ablocks[1][i] ) ) continue; ltmp_ind[nactive_atoms]=i; ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] ); nactive_atoms++; } } // Build the lists for the link cells linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() ); if( !usespecies ){ // Get some parallel info unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); if( serialCalculation() ){ stride=1; rank=0; } // Ensure we only do tasks where atoms are in appropriate link cells std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); std::vector<unsigned> active_tasks( getFullNumberOfTasks(), 0 ); for(unsigned i=rank;i<ablocks[0].size();i+=stride){ if( !isCurrentlyActive( ablocks[0][i] ) ) continue; natomsper=1; linked_atoms[0]=ltmp_ind[0]; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); for(unsigned j=0;j<natomsper;++j){ for(unsigned k=bookeeping(i,linked_atoms[j]).first;k<bookeeping(i,linked_atoms[j]).second;++k) active_tasks[k]=1; } } if( !serialCalculation() ) comm.Sum( active_tasks ); deactivateAllTasks(); activateTheseTasks( active_tasks ); contributorsAreUnlocked=false; } }
void MultiColvarBase::setupLinkCells(){ if( !linkcells.enabled() ) return ; unsigned iblock; if( usespecies ){ iblock=0; } else if( ablocks.size()<4 ){ iblock=1; } else { plumed_error(); } // Count number of currently active atoms unsigned nactive_atoms=0; for(unsigned i=0;i<ablocks[iblock].size();++i){ if( isCurrentlyActive( iblock, ablocks[iblock][i] ) ) nactive_atoms++; } std::vector<Vector> ltmp_pos( nactive_atoms ); std::vector<unsigned> ltmp_ind( nactive_atoms ); nactive_atoms=0; if( usespecies ){ for(unsigned i=0;i<ablocks[0].size();++i){ if( !isCurrentlyActive( 0, ablocks[0][i] ) ) continue; ltmp_ind[nactive_atoms]=ablocks[0][i]; ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ltmp_ind[nactive_atoms] ); nactive_atoms++; } } else { for(unsigned i=0;i<ablocks[1].size();++i){ if( !isCurrentlyActive( 1, ablocks[1][i] ) ) continue; ltmp_ind[nactive_atoms]=i; ltmp_pos[nactive_atoms]=getPositionOfAtomForLinkCells( ablocks[1][i] ); nactive_atoms++; } } // Build the lists for the link cells linkcells.buildCellLists( ltmp_pos, ltmp_ind, getPbc() ); if( !usespecies ){ // Get some parallel info unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); if( serialCalculation() ){ stride=1; rank=0; } // Ensure we only do tasks where atoms are in appropriate link cells std::vector<unsigned> linked_atoms( 1+ablocks[1].size() ); std::vector<unsigned> active_tasks( getFullNumberOfTasks(), 0 ); for(unsigned i=rank;i<ablocks[0].size();i+=stride){ if( !isCurrentlyActive( 0, ablocks[0][i] ) ) continue; unsigned natomsper=1; linked_atoms[0]=ltmp_ind[0]; // Note we always check atom 0 because it is simpler than changing LinkCells.cpp linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms ); for(unsigned j=0;j<natomsper;++j){ for(unsigned k=bookeeping(i,linked_atoms[j]).first;k<bookeeping(i,linked_atoms[j]).second;++k) active_tasks[k]=1; } } if( !serialCalculation() ) comm.Sum( active_tasks ); deactivateAllTasks(); activateTheseTasks( active_tasks ); contributorsAreUnlocked=false; } else { // Now check for calculating volumes (currently this is only done for usespecies style commands // as it is difficult to do with things like DISTANCES or ANGLES and I think pointless bool justVolumes=true; for(unsigned i=0;i<getNumberOfVessels();++i){ vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) ); if( !myb ){ justVolumes=false; break; } ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); if( !myv ){ justVolumes=false; break; } } // Now ensure that we only do calculations for those atoms in the relevant volume if( justVolumes ){ bool justVolumes=true; // Setup the regions in the action volume objects for(unsigned i=0;i<getNumberOfVessels();++i){ vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(i) ); ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); myv->retrieveAtoms(); myv->setupRegions(); } unsigned stride=comm.Get_size(); unsigned rank=comm.Get_rank(); if( serialCalculation() ){ stride=1; rank=0; } unsigned nactive=0; std::vector<unsigned> active_tasks( getFullNumberOfTasks(), 0 ); for(unsigned i=rank;i<getFullNumberOfTasks();i+=stride){ bool invol=false; for(unsigned j=0;j<getNumberOfVessels();++j){ vesselbase::BridgeVessel* myb=dynamic_cast<vesselbase::BridgeVessel*>( getPntrToVessel(j) ); ActionVolume* myv=dynamic_cast<ActionVolume*>( myb->getOutputAction() ); if( myv->inVolumeOfInterest(i) ){ invol=true; } } if( invol ){ nactive++; active_tasks[i]=1; } } if( !serialCalculation() ) comm.Sum( active_tasks ); deactivateAllTasks(); activateTheseTasks( active_tasks ); contributorsAreUnlocked=false; } } }