OpenLB 1.7
Loading...
Searching...
No Matches
surfaceForce.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022 Nicolas Hafen, Mathias J. Krause
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24
25#ifndef SURFACE_FORCE_COMMUNICATION_H
26#define SURFACE_FORCE_COMMUNICATION_H
27
28//Increase verbosity for further development
29//#define VERBOSE_COMMUNICATION
30
31namespace olb {
32
33namespace particles {
34
35namespace communication {
36
37
38
39#ifdef PARALLEL_MODE_MPI
40
41//Communicate particle surface force to cores containing their centres
42template<typename T, typename PARTICLETYPE, unsigned forceDataSize>
45 std::map<std::size_t, Vector<T,forceDataSize>>& globalIdDataMap
46#ifdef PARALLEL_MODE_MPI
47 , MPI_Comm surfaceForceComm
48#endif
49 )
50{
51 //TODO: add intra and inter core differentiation
52 using namespace descriptors;
53 //Retrieve dimensions
54 constexpr unsigned D = PARTICLETYPE::d;
55 constexpr unsigned Drot = utilities::dimensions::convert<D>::rotation;
56 //Retrieve loadBalancer
57 auto& superStructure = sParticleSystem.getSuperStructure();
58 auto& loadBalancer = superStructure.getLoadBalancer();
59
60 //Create FieldArrayD for globalID, force and torque
62 using FORCING_EVAL = typename PARTICLETYPE
63 ::template derivedField<descriptors::FORCING>;
64 using TORQUE_EVAL = typename FORCING_EVAL
65 ::template derivedField<descriptors::TORQUE>;
68
69 //Create communicatables
70 auto communicatableForce = ConcreteCommunicatable(fieldForce);
71 auto communicatableTorque = ConcreteCommunicatable(fieldTorque);
72 auto communicatableID = ConcreteCommunicatable(fieldID);
73 //Retrieve serial size
74 const std::vector<unsigned int> indices{0};
75 auto serialSize = communicatableForce.size(indices)
76 + communicatableTorque.size(indices)
77 + communicatableID.size(indices);
78 //Create rankDataMap
79 std::multimap<int,std::unique_ptr<std::uint8_t[]>> rankDataMap;
80
81 //Loop over valid particles in particle system
84 [&](Particle<T,PARTICLETYPE>& particle,
85 ParticleSystem<T,PARTICLETYPE>& particleSystem, int globiC){
86 //Retrieve globiC of particle center
87 int globiCcentre = particle.template getField<PARALLELIZATION,IC>();
88 int rankDest = loadBalancer.rank(globiCcentre);
89 //Retrieve force and torque and set FieldArray
90 auto force = particle.template getField<FORCING,FORCE>();
91 auto torque = particle.template getField<FORCING,TORQUE>();
92 auto globalID = particle.template getField<PARALLELIZATION,ID>();
93#ifdef VERBOSE_COMMUNICATION
94 std::cout << "EVALUATING: force=" << force << ", torque=" << torque << ", globalID=" << globalID << std::endl;
95#endif
96 fieldForce.setField(0, force);
97 fieldTorque.setField(0, torque);
98 fieldID.setField(0, globalID);
99 //Create buffer
100 std::unique_ptr<std::uint8_t[]> buffer(new std::uint8_t[serialSize]{ });
101 std::uint8_t* bufferRaw = buffer.get();
102 //Serialize force
103 std::size_t serialIdx = communicatableForce.serialize(indices, bufferRaw);
104 //Serialice torque with offset serialIdx
105 serialIdx += communicatableTorque.serialize(indices, &bufferRaw[serialIdx]);
106 //Serialice globalID with offset serialIdx
107 communicatableID.serialize(indices, &bufferRaw[serialIdx]);
108 //Add serialized data to rankDataMap
109 rankDataMap.insert(std::make_pair(rankDest, std::move(buffer)));
110 }); //forParticlesInSuperParticleSystem()
111
112 //Retrieve rank of direct neighbours
113 auto& listNeighbourRanks = sParticleSystem.getNeighbourRanks();
114
115 //Create non blocking mpi helper
117
118 //Create ranDataMapSorted (WARNING: has to be existent until all data is received! c.f. #290)
119 std::map<int, std::vector<std::uint8_t> > rankDataMapSorted;
120
121 //Fill send buffer
122 fillSendBuffer( rankDataMap, rankDataMapSorted, serialSize );
123
124 //Send mapped data
125 communication::sendMappedData( rankDataMapSorted,
126 listNeighbourRanks, serialSize, surfaceForceComm, mpiNbHelper );
127
128 //Receive data and iterate buffer
129 communication::receiveAndExecuteForData( listNeighbourRanks, serialSize,
130 surfaceForceComm, mpiNbHelper,
131 [&](int rankOrig, std::uint8_t* bufferRaw){
132 //Deserialize force
133 std::size_t serialIdx = communicatableForce.deserialize(indices, bufferRaw);
134 //Deserialize torque with offset serialIdx
135 serialIdx += communicatableTorque.deserialize(indices, &bufferRaw[serialIdx]);
136 //Deserialize globalID with offset serialIdx
137 communicatableID.deserialize(indices, &bufferRaw[serialIdx]);
138 //Retrieve vectors
139 auto force = fieldForce.getField(0);
140 auto torque = fieldTorque.getField(0);
141 auto globalID = fieldID.getField(0);
142
143#ifdef VERBOSE_COMMUNICATION
144 int rank = singleton::mpi().getRank();
145 std::cout << "Received (on rank=" << rank
146 << " from rank=" << rankOrig
147 << "): force=" << force
148 << std::endl
149 << " "
150 << ", torque=" << torque
151 << ", globalID=" << globalID
152 << std::endl;
153#endif
154
155 //Create forceData Vector
156 Vector<T,forceDataSize> forceData;
157 for (unsigned iDim=0; iDim<D; ++iDim) {
158 forceData[iDim] = force[iDim];
159 }
160
162 forceData[D] = torque;
163 }
164 else {
165 for (unsigned iDim=0; iDim<Drot; ++iDim) {
166 forceData[iDim+D] = torque[iDim];
167 }
168 }
169
170 //Add id-data-pair to map OR only add data
171 auto mapPair = globalIdDataMap.insert( std::pair<std::size_t,
172 Vector<T,forceDataSize>>(globalID, forceData) );
173 if (mapPair.second==false){ //Checks previous existance
174 globalIdDataMap[globalID] += forceData;
175 }
176 }); //receiveAndExecuteForData()
177}
178
179#endif
180
181
182//Assign (communicated) surface force to particle
183//- by matchin its globalID
184template<typename T, typename PARTICLETYPE, unsigned forceDataSize>
187 std::map<std::size_t, Vector<T,forceDataSize>>& globalIdDataMap )
188{
189 using namespace descriptors;
190 //Retrieve dimension
191 constexpr unsigned D = PARTICLETYPE::d;
192 constexpr unsigned Drot = utilities::dimensions::convert<D>::rotation;
193 //Loop over particle systems
195 [&](ParticleSystem<T,PARTICLETYPE>& particleSystem, int iC,
196 int globiC){
197 //Loop over globalIdDataPairs
198 for ( auto globalIdDataPair : globalIdDataMap ){
199 //Loop over particles
200 // -! Lambda-expression unavailable due to break command
201 for (std::size_t iP=0; iP<particleSystem.size(); ++iP){
202 auto particle = particleSystem.get(iP);
203 //Only consider valid particle centres
204 if (conditions::valid_particle_centres::value(particle, globiC)){
205 //Retrieve globalIDs
206 std::size_t globalID = globalIdDataPair.first;
207 std::size_t globalIDiP = particle.template getField<PARALLELIZATION,ID>();
208 //Check whether globalID matches
209 if (globalIDiP==globalID){
210 //Retrieve force data
211 auto forceData = globalIdDataPair.second;
212 auto force = particle.template getField<FORCING,FORCE>();
213 auto torque = particle.template getField<FORCING,TORQUE>();
214 //Add force to particle
215 for (unsigned iDim=0; iDim<D; ++iDim) {
216 force[iDim] += forceData[iDim];
217 }
218 //Add torque to particle
220 torque += forceData[D];
221 }
222 else {
223 for (unsigned iDim=0; iDim<Drot; ++iDim) {
224 torque[iDim] += forceData[iDim+D];
225 }
226 }
227
228#ifdef VERBOSE_COMMUNICATION
229 int rank = singleton::mpi().getRank();
230 std::cout << "Assigned (on rank=" << rank
231 << "): force=" << force
232 << std::endl
233 << " "
234 << ", torque=" << torque
235 << ", globalID=" << globalID
236 << std::endl;
237#endif
238 //Update particle
239 particle.template setField<FORCING,FORCE>( force );
240 particle.template setField<FORCING,TORQUE>( torque );
241 //Break, since particle already found
242 break;
243 }
244 }
245 }
246 }
247 });
248}
249
250
251} //namespace communication
252
253} //namespace particles
254
255} //namespace olb
256
257
258#endif
SoA storage for instances of a single FIELD.
auto getField(std::size_t iCell) const
Return copy of FIELD data for cell iCell.
void setField(std::size_t iCell, const FieldD< T, DESCRIPTOR, FIELD > &v)
Set FIELD data at cell iCell.
LoadBalancer< T > & getLoadBalancer()
Read and write access to the load balancer.
Plain old scalar vector.
Definition vector.h:47
auto & get()
Expose container.
constexpr std::size_t size()
Size of ParticleSystem.
SuperStructure< T, PARTICLETYPE::d > & getSuperStructure()
const std::unordered_set< int > & getNeighbourRanks()
int getRank() const
Returns the process ID.
Helper class for non blocking MPI communication.
Definition mpiManager.h:51
void receiveAndExecuteForData(const std::unordered_set< int > &availableRanks, std::size_t serialSize, MPI_Comm Comm, singleton::MpiNonBlockingHelper &mpiNbHelper, F f)
Definition relocation.h:572
void forSystemsInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
void communicateSurfaceForce(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::map< std::size_t, Vector< T, forceDataSize > > &globalIdDataMap, MPI_Comm surfaceForceComm)
void sendMappedData(std::map< int, std::vector< std::uint8_t > > &rankDataMapSorted, const std::unordered_set< int > &availableRanks, const std::size_t serialSize, MPI_Comm Comm, singleton::MpiNonBlockingHelper &mpiNbHelper)
Definition relocation.h:408
void fillSendBuffer(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &rankDataMap, std::map< int, std::vector< std::uint8_t > > &rankDataMapSorted, std::size_t serialSize)
Definition relocation.h:387
void assignSurfaceForce(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::map< std::size_t, Vector< T, forceDataSize > > &globalIdDataMap)
void forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
MpiManager & mpi()
Top level namespace for all of OpenLB.
static bool value(Particle< T, PARTICLETYPE > &particle, int globiC)
Converts dimensions by deriving from given cartesian dimension D.