mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
BUG: UOPstream indexes out of bounds after whitespace stripping (fixes #134)
- only affects transfer of C-style string with a single character
remaining after whitespace stripping. Test added into Test-parallel.
- Note some idiosyncrasies in the behaviour:
send | receives
-------------------------+-------------------------
string("a b c") | string "a b c"
string("a") | string "a"
"a b c" | word "abc"
'd' | char 'd'
"d" | char 'd'
"d " | char 'd'
This commit is contained in:
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -42,154 +42,235 @@ Description
|
|||||||
|
|
||||||
using namespace Foam;
|
using namespace Foam;
|
||||||
|
|
||||||
|
|
||||||
|
void testMapDistribute()
|
||||||
|
{
|
||||||
|
Random rndGen(43544*Pstream::myProcNo());
|
||||||
|
|
||||||
|
// Generate random data.
|
||||||
|
List<Tuple2<label, List<scalar>>> complexData(100);
|
||||||
|
forAll(complexData, i)
|
||||||
|
{
|
||||||
|
complexData[i].first() = rndGen.integer(0, Pstream::nProcs()-1);
|
||||||
|
complexData[i].second().setSize(3);
|
||||||
|
complexData[i].second()[0] = 1;
|
||||||
|
complexData[i].second()[1] = 2;
|
||||||
|
complexData[i].second()[2] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all ones to processor indicated by .first()
|
||||||
|
|
||||||
|
// Count how many to send
|
||||||
|
labelList nSend(Pstream::nProcs(), 0);
|
||||||
|
forAll(complexData, i)
|
||||||
|
{
|
||||||
|
label procI = complexData[i].first();
|
||||||
|
nSend[procI]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect items to be sent
|
||||||
|
labelListList sendMap(Pstream::nProcs());
|
||||||
|
forAll(sendMap, procI)
|
||||||
|
{
|
||||||
|
sendMap[procI].setSize(nSend[procI]);
|
||||||
|
}
|
||||||
|
nSend = 0;
|
||||||
|
forAll(complexData, i)
|
||||||
|
{
|
||||||
|
label procI = complexData[i].first();
|
||||||
|
sendMap[procI][nSend[procI]++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync how many to send
|
||||||
|
labelList nRecv;
|
||||||
|
Pstream::exchangeSizes(sendMap, nRecv);
|
||||||
|
|
||||||
|
// Collect items to be received
|
||||||
|
labelListList recvMap(Pstream::nProcs());
|
||||||
|
forAll(recvMap, procI)
|
||||||
|
{
|
||||||
|
recvMap[procI].setSize(nRecv[procI]);
|
||||||
|
}
|
||||||
|
|
||||||
|
label constructSize = 0;
|
||||||
|
// Construct with my own elements first
|
||||||
|
forAll(recvMap[Pstream::myProcNo()], i)
|
||||||
|
{
|
||||||
|
recvMap[Pstream::myProcNo()][i] = constructSize++;
|
||||||
|
}
|
||||||
|
// Construct from other processors
|
||||||
|
forAll(recvMap, procI)
|
||||||
|
{
|
||||||
|
if (procI != Pstream::myProcNo())
|
||||||
|
{
|
||||||
|
forAll(recvMap[procI], i)
|
||||||
|
{
|
||||||
|
recvMap[procI][i] = constructSize++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct distribute map (destructively)
|
||||||
|
mapDistribute map(constructSize, sendMap.xfer(), recvMap.xfer());
|
||||||
|
|
||||||
|
// Distribute complexData
|
||||||
|
map.distribute(complexData);
|
||||||
|
|
||||||
|
Pout<< "complexData:" << complexData << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void testTransfer(const T& input)
|
||||||
|
{
|
||||||
|
T data = input;
|
||||||
|
|
||||||
|
if (Pstream::master())
|
||||||
|
{
|
||||||
|
Perr<<"test transfer (" << (typeid(T).name()) << "): " << data << nl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pstream::myProcNo() != Pstream::masterNo())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Perr<< "slave sending to master " << Pstream::masterNo() << endl;
|
||||||
|
OPstream toMaster(Pstream::blocking, Pstream::masterNo());
|
||||||
|
toMaster << data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Perr<< "slave receiving from master " << Pstream::masterNo() << endl;
|
||||||
|
IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
|
||||||
|
fromMaster >> data;
|
||||||
|
Perr<< data << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for
|
||||||
|
(
|
||||||
|
int slave = Pstream::firstSlave();
|
||||||
|
slave <= Pstream::lastSlave();
|
||||||
|
++slave
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Perr<< "master receiving from slave " << slave << endl;
|
||||||
|
IPstream fromSlave(Pstream::blocking, slave);
|
||||||
|
fromSlave >> data;
|
||||||
|
Perr<< data << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for
|
||||||
|
(
|
||||||
|
int slave = Pstream::firstSlave();
|
||||||
|
slave <= Pstream::lastSlave();
|
||||||
|
++slave
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Perr<< "master sending to slave " << slave << endl;
|
||||||
|
OPstream toSlave(Pstream::blocking, slave);
|
||||||
|
toSlave << data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void testTokenized(const T& data)
|
||||||
|
{
|
||||||
|
token tok;
|
||||||
|
|
||||||
|
if (Pstream::master())
|
||||||
|
{
|
||||||
|
Perr<<"test tokenized \"" << data << "\"" << nl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Pstream::myProcNo() != Pstream::masterNo())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Perr<< "slave sending to master " << Pstream::masterNo() << endl;
|
||||||
|
OPstream toMaster(Pstream::blocking, Pstream::masterNo());
|
||||||
|
toMaster << data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Perr<< "slave receiving from master " << Pstream::masterNo() << endl;
|
||||||
|
IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
|
||||||
|
|
||||||
|
fromMaster >> tok;
|
||||||
|
Perr<< tok.info() << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for
|
||||||
|
(
|
||||||
|
int slave = Pstream::firstSlave();
|
||||||
|
slave <= Pstream::lastSlave();
|
||||||
|
++slave
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Perr<< "master receiving from slave " << slave << endl;
|
||||||
|
IPstream fromSlave(Pstream::blocking, slave);
|
||||||
|
fromSlave >> tok;
|
||||||
|
Perr<< tok.info() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for
|
||||||
|
(
|
||||||
|
int slave = Pstream::firstSlave();
|
||||||
|
slave <= Pstream::lastSlave();
|
||||||
|
++slave
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Perr<< "master sending to slave " << slave << endl;
|
||||||
|
OPstream toSlave(Pstream::blocking, slave);
|
||||||
|
toSlave << data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
#include "setRootCase.H"
|
#include "setRootCase.H"
|
||||||
#include "createTime.H"
|
#include "createTime.H"
|
||||||
|
|
||||||
|
testMapDistribute();
|
||||||
|
|
||||||
// Test mapDistribute
|
if (!Pstream::parRun())
|
||||||
// ~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
if (true)
|
|
||||||
{
|
{
|
||||||
Random rndGen(43544*Pstream::myProcNo());
|
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
|
||||||
|
return 0;
|
||||||
// Generate random data.
|
|
||||||
List<Tuple2<label, List<scalar>>> complexData(100);
|
|
||||||
forAll(complexData, i)
|
|
||||||
{
|
|
||||||
complexData[i].first() = rndGen.integer(0, Pstream::nProcs()-1);
|
|
||||||
complexData[i].second().setSize(3);
|
|
||||||
complexData[i].second()[0] = 1;
|
|
||||||
complexData[i].second()[1] = 2;
|
|
||||||
complexData[i].second()[2] = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all ones to processor indicated by .first()
|
|
||||||
|
|
||||||
|
|
||||||
// Count how many to send
|
|
||||||
labelList nSend(Pstream::nProcs(), 0);
|
|
||||||
forAll(complexData, i)
|
|
||||||
{
|
|
||||||
label procI = complexData[i].first();
|
|
||||||
nSend[procI]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect items to be sent
|
|
||||||
labelListList sendMap(Pstream::nProcs());
|
|
||||||
forAll(sendMap, procI)
|
|
||||||
{
|
|
||||||
sendMap[procI].setSize(nSend[procI]);
|
|
||||||
}
|
|
||||||
nSend = 0;
|
|
||||||
forAll(complexData, i)
|
|
||||||
{
|
|
||||||
label procI = complexData[i].first();
|
|
||||||
sendMap[procI][nSend[procI]++] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync how many to send
|
|
||||||
labelList nRecv;
|
|
||||||
Pstream::exchangeSizes(sendMap, nRecv);
|
|
||||||
|
|
||||||
// Collect items to be received
|
|
||||||
labelListList recvMap(Pstream::nProcs());
|
|
||||||
forAll(recvMap, procI)
|
|
||||||
{
|
|
||||||
recvMap[procI].setSize(nRecv[procI]);
|
|
||||||
}
|
|
||||||
|
|
||||||
label constructSize = 0;
|
|
||||||
// Construct with my own elements first
|
|
||||||
forAll(recvMap[Pstream::myProcNo()], i)
|
|
||||||
{
|
|
||||||
recvMap[Pstream::myProcNo()][i] = constructSize++;
|
|
||||||
}
|
|
||||||
// Construct from other processors
|
|
||||||
forAll(recvMap, procI)
|
|
||||||
{
|
|
||||||
if (procI != Pstream::myProcNo())
|
|
||||||
{
|
|
||||||
forAll(recvMap[procI], i)
|
|
||||||
{
|
|
||||||
recvMap[procI][i] = constructSize++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Construct distribute map (destructively)
|
|
||||||
mapDistribute map(constructSize, sendMap.xfer(), recvMap.xfer());
|
|
||||||
|
|
||||||
// Distribute complexData
|
|
||||||
map.distribute(complexData);
|
|
||||||
|
|
||||||
Pout<< "complexData:" << complexData << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Info<< "\nStarting transfers\n\n" << endl;
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
testTransfer(vector(0, 1, 2));
|
||||||
|
testTransfer(label(1234));
|
||||||
|
testTransfer(scalar(3.14159));
|
||||||
|
testTransfer(string("test string"));
|
||||||
|
testTransfer(string(" x "));
|
||||||
|
testTransfer(word("3.141 59")); // bad word, but transfer doesn't care
|
||||||
|
|
||||||
Perr<< "\nStarting transfers\n" << endl;
|
testTokenized(label(1234));
|
||||||
|
testTokenized(scalar(3.14159));
|
||||||
|
testTokenized('a');
|
||||||
|
testTokenized('$'); // will not tokenize well
|
||||||
|
|
||||||
vector data(0, 1, 2);
|
testTokenized(string("test string1"));
|
||||||
|
testTokenized("test string1");
|
||||||
|
testTokenized(word("3.141 59")); // bad word, but transfer doesn't care
|
||||||
|
|
||||||
if (Pstream::parRun())
|
testTokenized(string(" a "));
|
||||||
{
|
testTokenized(" a ");
|
||||||
if (Pstream::myProcNo() != Pstream::masterNo())
|
|
||||||
{
|
|
||||||
{
|
|
||||||
Perr<< "slave sending to master "
|
|
||||||
<< Pstream::masterNo() << endl;
|
|
||||||
OPstream toMaster(Pstream::blocking, Pstream::masterNo());
|
|
||||||
toMaster << data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Perr<< "slave receiving from master "
|
testTokenized(string(" $ "));
|
||||||
<< Pstream::masterNo() << endl;
|
testTokenized(" $ "); // reduces to 'char' and will not tokenize well
|
||||||
IPstream fromMaster(Pstream::blocking, Pstream::masterNo());
|
|
||||||
fromMaster >> data;
|
|
||||||
|
|
||||||
Perr<< data << endl;
|
testTokenized(string(" $$ "));
|
||||||
}
|
testTokenized(" $$ "); // reduces to 'word' and is tagged as such
|
||||||
else
|
|
||||||
{
|
|
||||||
for
|
|
||||||
(
|
|
||||||
int slave=Pstream::firstSlave();
|
|
||||||
slave<=Pstream::lastSlave();
|
|
||||||
slave++
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Perr << "master receiving from slave " << slave << endl;
|
|
||||||
IPstream fromSlave(Pstream::blocking, slave);
|
|
||||||
fromSlave >> data;
|
|
||||||
|
|
||||||
Perr<< data << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for
|
|
||||||
(
|
|
||||||
int slave=Pstream::firstSlave();
|
|
||||||
slave<=Pstream::lastSlave();
|
|
||||||
slave++
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Perr << "master sending to slave " << slave << endl;
|
|
||||||
OPstream toSlave(Pstream::blocking, slave);
|
|
||||||
toSlave << data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Info<< "End\n" << endl;
|
Info<< "End\n" << endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
\\ / O peration |
|
\\ / O peration |
|
||||||
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
|
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
|
||||||
\\/ M anipulation |
|
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -194,7 +194,7 @@ Foam::Ostream& Foam::UOPstream::write(const char* str)
|
|||||||
|
|
||||||
if (nonWhiteChars.size() == 1)
|
if (nonWhiteChars.size() == 1)
|
||||||
{
|
{
|
||||||
return write(nonWhiteChars.c_str()[1]);
|
return write(nonWhiteChars[0]);
|
||||||
}
|
}
|
||||||
else if (nonWhiteChars.size())
|
else if (nonWhiteChars.size())
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user