diff --git a/applications/utilities/displacementField/Make/files b/applications/utilities/displacementField/Make/files new file mode 100644 index 00000000..816a220c --- /dev/null +++ b/applications/utilities/displacementField/Make/files @@ -0,0 +1,3 @@ +displacementField.C + +EXE = $(CFDEM_APP_DIR)/displacementField diff --git a/applications/utilities/displacementField/Make/options b/applications/utilities/displacementField/Make/options new file mode 100644 index 00000000..d27c95d0 --- /dev/null +++ b/applications/utilities/displacementField/Make/options @@ -0,0 +1,7 @@ +EXE_INC = \ + -I$(LIB_SRC)/finiteVolume/lnInclude \ + -I$(LIB_SRC)/meshTools/lnInclude + +EXE_LIBS = \ + -lfiniteVolume \ + -lmeshTools diff --git a/applications/utilities/displacementField/displacementField.C b/applications/utilities/displacementField/displacementField.C new file mode 100644 index 00000000..307fcac4 --- /dev/null +++ b/applications/utilities/displacementField/displacementField.C @@ -0,0 +1,393 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Website: https://openfoam.org + \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +Application + displacementField + +\*---------------------------------------------------------------------------*/ + +#include "fvCFD.H" +#include "vectorList.H" +#include +#include +#include +#include +#include + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +void findPairs(labelList &, labelList &, labelPairList &); +void findPairsUnordered(labelList &, labelList &, labelPairList &); +void interpolateCellValues(fvMesh &, label , labelList &, volVectorField &, volVectorField &, scalarList &, scalar); +void nearestNeighborCells(fvMesh &, label, label, labelList &, labelList &); +void readDump(std::string, labelList &, vectorList &); +scalar weightFun(scalar); + +int main(int argc, char *argv[]) +{ + argList::addOption + ( + "totalProcs", + "label", + "total number of parallel processes, defaults to 1" + ); + argList::addOption + ( + "thisProc", + "label", + "number of current process, defaults to 0" + ); + + + #include "setRootCase.H" + #include "createTime.H" + #include "createMesh.H" + + const label thisProc = args.optionLookupOrDefault("thisProc", 0); + const label totalProcs = args.optionLookupOrDefault("totalProcs", 1); + + Info << "This is number " << thisProc << " of " << totalProcs << " processes." << endl; + + + // user-defined input for each case + IOdictionary displacementProperties + ( + IOobject + ( + "displacementProperties", + mesh.time().constant(), + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ) + ); + + label dumpIndexStart(readLabel(displacementProperties.lookup("dumpIndexStart"))); + label dumpIndexIncrement(readLabel(displacementProperties.lookup("dumpIndexIncrement"))); + label nNeighMin(readLabel(displacementProperties.lookup("nNeighMin"))); + scalar timePerStep(readScalar(displacementProperties.lookup("timePerStep"))); + scalar startTime(readScalar(displacementProperties.lookup("startTime"))); + std::string filepath=string(displacementProperties.lookup("filepath")); + std::string fileext=string(displacementProperties.lookupOrDefault("fileextension","")); + bool fillEmptyCells=bool(displacementProperties.lookupOrDefault("fillEmptyCells",true)); + scalar xmin=scalar(displacementProperties.lookupOrDefault("xmin",-1e10)); + scalar xmax=scalar(displacementProperties.lookupOrDefault("xmax",1e10)); + scalar ymin=scalar(displacementProperties.lookupOrDefault("ymin",-1e10)); + scalar ymax=scalar(displacementProperties.lookupOrDefault("ymax",1e10)); + scalar zmin=scalar(displacementProperties.lookupOrDefault("zmin",-1e10)); + scalar zmax=scalar(displacementProperties.lookupOrDefault("zmax",1e10)); + scalarList boundaries(6); + boundaries[0]=xmin; + boundaries[1]=xmax; + boundaries[2]=ymin; + boundaries[3]=ymax; + boundaries[4]=zmin; + boundaries[5]=zmax; + + + label dumpIndex1 = dumpIndexStart + thisProc * dumpIndexIncrement; + label dumpIndex2 = dumpIndex1 + dumpIndexIncrement; + + volVectorField Us + ( + IOobject + ( + "UDisp", + runTime.timeName(), + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh, + dimensionedVector("zero", dimensionSet(0,1,-1,0,0), vector::zero) + ); + + volVectorField UsDirectedVariance + ( + IOobject + ( + "UDispDirectedVariance", + runTime.timeName(), + mesh, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh, + dimensionedVector("zero", dimensionSet(0,1,-1,0,0), vector::zero) + ); + + scalar currTime=startTime + thisProc * timePerStep; + label timeIndex=thisProc; + + while(true) + { + runTime.setTime(currTime,timeIndex); + // read dump files and check which particle indices are present in both + labelList indices1, indices2; + vectorList positions1, positions2; + + std::stringstream ss; + ss << filepath << dumpIndex1 << fileext; + std::string filename1 = ss.str(); + ss.str(""); + ss << filepath << dumpIndex2 << fileext; + std::string filename2 = ss.str(); + + if (access( filename1.c_str(), F_OK ) == -1 || access( filename2.c_str(), F_OK ) == -1) break; + + Info << "\nReading" << endl; + Info << "\t" << filename1 << endl; + Info << "\t" << filename2 << endl; + Info << "corresponding to time = " << currTime << "." << endl; + + readDump(filename1, indices1, positions1); + readDump(filename2, indices2, positions2); + + labelPairList pairs; + findPairs(indices1,indices2,pairs); + + // average particle displacements and their variance + Info << "Binning particle displacements on mesh." << endl; + labelList particlesInCell(mesh.nCells(), 0); + vector position, displacement; + label line1, line2; + label cellI; + + Us *= 0.0; + UsDirectedVariance *= 0.0; + for (label partI = 0; partI < pairs.size(); partI++) + { + line1 = pairs[partI].first(); + line2 = pairs[partI].second(); + position = positions1[line1]; + displacement = positions2[line2] - positions1[line1]; + cellI = mesh.findCell(position); + if (cellI < 0) continue; + particlesInCell[cellI] += 1; + Us[cellI] += displacement; + + for (label comp=0;comp<3;comp++) + { + UsDirectedVariance[cellI].component(comp) += displacement.component(comp)*displacement.component(comp); + } + } + + + for (label cellJ = 0; cellJ 0) + { + Us[cellJ] /= particlesInCell[cellJ]; + UsDirectedVariance[cellJ] /= particlesInCell[cellJ]; + for (label comp=0;comp<3;comp++) + { + UsDirectedVariance[cellJ].component(comp) -= Us[cellJ].component(comp)*Us[cellJ].component(comp); + if (UsDirectedVariance[cellJ].component(comp) > 0) UsDirectedVariance[cellJ].component(comp) = Foam::sqrt(UsDirectedVariance[cellJ].component(comp)); + } + } + } + + + // interpolate values for empty cells + if (fillEmptyCells) + { + Info << "Interpolating empty cells." << endl; + interpolateCellValues(mesh,nNeighMin,particlesInCell,Us,UsDirectedVariance,boundaries,timePerStep); + } + +// dumpIndex1 = dumpIndex2; +// dumpIndex2 = dumpIndex1 + dumpIndexIncrement; + dumpIndex1 += dumpIndexIncrement*totalProcs; + dumpIndex2 += dumpIndexIncrement*totalProcs; + + Us /= timePerStep; + UsDirectedVariance /= timePerStep; + Us.write(); + UsDirectedVariance.write(); + currTime += timePerStep*totalProcs; + timeIndex += totalProcs; + } + return 0; +} + +void readDump(std::string filename, labelList &indices, vectorList &positions) +{ + #include + + const label leadingLines = 9; + label lineCounter = 0; + label partIndex; + scalar x, y, z; + + indices.clear(); + positions.clear(); + + std::ifstream file(filename); + std::string str; + while (std::getline(file, str)) + { + if (lineCounter >= leadingLines) + { + sscanf(str.c_str(), "%d %lf %lf %lf", &partIndex, &x, &y, &z); + indices.append(partIndex); + positions.append(vector(x,y,z)); + } + lineCounter++; + } +} + +void findPairs(labelList &indices1, labelList &indices2, labelPairList &pairs) +{ + // remove all entries from first list if they are not present in second list + // this assumes ordered entries + + if (indices2.size() == 0) return; + + for (label i=0;i index1) j2 = jmid; + else if (indices2[jmid] < index1) j1 = jmid; + else + { + pairs.append(labelPair(i,jmid)); + break; + } + if (j2-j1 == 1) break; + } + } + Info << "findPairs: " << pairs.size() << " pairs found." << endl; +} + +void findPairsUnordered(labelList &indices1, labelList &indices2, labelPairList &pairs) +{ + // remove all entries from first list if they are not present in second list + + for (label i=0;i 0) continue; + + vector position = mesh.C()[cellI]; + if (position.x() < boundaries[0] || position.x() > boundaries[1]) continue; + if (position.y() < boundaries[2] || position.y() > boundaries[3]) continue; + if (position.z() < boundaries[4] || position.z() > boundaries[5]) continue; + + nearestNeighborCells(mesh, cellI, nNeighMin, particlesInCell, neighborsWithValues); + weightSum = 0.0; + weights.clear(); + for (label neighI=0; neighI neighbors; + std::set