Merge branch 'develop-pre-release' of develop.openfoam.com:Development/OpenFOAM-plus into develop-pre-release

This commit is contained in:
sergio
2018-05-18 01:31:17 -07:00
213 changed files with 58016 additions and 3055 deletions

View File

@ -3,7 +3,7 @@ cd ${0%/*} || exit 1 # Run from this directory
#------------------------------------------------------------------------------
wmake libso CompressibleTwoPhaseMixtureTurbulenceModels
wmake
wmake $targetType CompressibleTwoPhaseMixtureTurbulenceModels
wmake $targetType
#------------------------------------------------------------------------------

View File

@ -1,11 +1,10 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
targetType=libso # Preferred library type
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
#------------------------------------------------------------------------------
wmake $targetType temperaturePhaseChangeTwoPhaseMixtures
wmake
wmake $targetType
#------------------------------------------------------------------------------

View File

@ -12,8 +12,8 @@ if have_cgal
then
wmake $targetType conformalVoronoiMesh
wmake $targetType conformalVoronoi2DMesh
wmake foamyQuadMesh
wmake foamyHexMesh
wmake $targetType foamyQuadMesh
wmake $targetType foamyHexMesh
# wmake foamyHexMeshBackgroundMesh
# (cd foamyHexMeshSurfaceSimplify && ./Allwmake)
# wmake cellSizeAndAlignmentGrid

View File

@ -356,6 +356,9 @@ int main(int argc, char *argv[])
)
);
// Give file handler a chance to determine the output directory
const_cast<fileOperation&>(fileHandler()).setNProcs(nDomains);
if (decomposeFieldsOnly)
{
// Sanity check on previously decomposed case
@ -395,22 +398,42 @@ int main(int argc, char *argv[])
Info<< "Removing " << nProcs
<< " existing processor directories" << endl;
fileHandler().rmDir
// Remove existing processors directory
fileNameList dirs
(
runTime.path()/word("processors"),
true // silent (may not have been collated)
);
// remove existing processor dirs
// reverse order to avoid gaps if someone interrupts the process
for (label proci = nProcs-1; proci >= 0; --proci)
{
fileName procDir
fileHandler().readDir
(
runTime.path()/(word("processor") + name(proci))
);
runTime.path(),
fileName::Type::DIRECTORY
)
);
forAllReverse(dirs, diri)
{
const fileName& d = dirs[diri];
fileHandler().rmDir(procDir);
// Starts with 'processors'
if (d.find("processors") == 0)
{
if (fileHandler().exists(d))
{
fileHandler().rmDir(d);
}
}
// Starts with 'processor'
if (d.find("processor") == 0)
{
// Check that integer after processor
fileName num(d.substr(9));
label proci = -1;
if (Foam::read(num.c_str(), proci))
{
if (fileHandler().exists(d))
{
fileHandler().rmDir(d);
}
}
}
}
procDirsProblem = false;

View File

@ -216,6 +216,9 @@ int main(int argc, char *argv[])
<< exit(FatalError);
}
// Warn fileHandler of number of processors
const_cast<fileOperation&>(fileHandler()).setNProcs(nProcs);
// Create the processor databases
PtrList<Time> databases(nProcs);

View File

@ -33,6 +33,7 @@ License
#include "Time.H"
#include "patchZones.H"
#include "IOobjectList.H"
#include "collatedFileOperation.H"
// VTK includes
#include "vtkDataArraySelection.h"
@ -268,7 +269,7 @@ Foam::word Foam::vtkPVFoam::getReaderPartName(const int partId) const
Foam::vtkPVFoam::vtkPVFoam
(
const char* const FileName,
const char* const vtkFileName,
vtkPVFoamReader* reader
)
:
@ -294,12 +295,19 @@ Foam::vtkPVFoam::vtkPVFoam
{
if (debug)
{
Info<< "vtkPVFoam - " << FileName << nl;
Info<< "vtkPVFoam - " << vtkFileName << nl;
printMemory();
}
fileName FileName(vtkFileName);
// Make sure not to use the threaded version - it does not like
// being loaded as a shared library - static cleanup order is problematic.
// For now just disable the threaded writer.
fileOperations::collatedFileOperation::maxThreadFileBufferSize = 0;
// avoid argList and get rootPath/caseName directly from the file
fileName fullCasePath(fileName(FileName).path());
fileName fullCasePath(FileName.path());
if (!isDir(fullCasePath))
{
@ -314,8 +322,20 @@ Foam::vtkPVFoam::vtkPVFoam
setEnv("FOAM_EXECUTABLE", "paraview", false);
// Set the case as an environment variable - some BCs might use this
if (fullCasePath.name().find("processors", 0) == 0)
{
// FileName e.g. "cavity/processors256/processor1.OpenFOAM
// Remove the processors section so it goes into processorDDD
// checking below.
fullCasePath = fullCasePath.path()/fileName(FileName.name()).lessExt();
}
if (fullCasePath.name().find("processor", 0) == 0)
{
// Give filehandler opportunity to analyse number of processors
(void)fileHandler().filePath(fullCasePath);
const fileName globalCase = fullCasePath.path();
setEnv("FOAM_CASE", globalCase, true);

View File

@ -2,6 +2,6 @@
cd ${0%/*} || exit 1 # Run from this directory
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
(wmake libso extractionMethod && wmake)
(wmake $targetType extractionMethod && wmake $targetType)
#------------------------------------------------------------------------------

View File

@ -5,7 +5,7 @@
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
// Insitu processing of finiteVolume fields with ParaView Catalyst
// Insitu processing with ParaView Catalyst
type catalyst;
libs ("libcatalystFoam.so");

View File

@ -0,0 +1,68 @@
from paraview.simple import *
from paraview import coprocessing
# The frequency to output everything
outputfrequency = 1
# Simply print out all channel names that our function object is producing
# ----------------------- CoProcessor definition -----------------------
def CreateCoProcessor():
def _CreatePipeline(coprocessor, datadescription):
class Pipeline:
for i in range(datadescription.GetNumberOfInputDescriptions()):
name = datadescription.GetInputDescriptionName(i)
input = coprocessor.CreateProducer(datadescription, name)
grid = input.GetClientSideObject().GetOutputDataObject(0)
print "Channel <" + name + "> is", grid.GetClassName()
return Pipeline()
class CoProcessor(coprocessing.CoProcessor):
def CreatePipeline(self, datadescription):
self.Pipeline = _CreatePipeline(self, datadescription)
return CoProcessor()
#--------------------------------------------------------------
# Global variables that will hold the pipeline for each timestep
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
# It will be automatically setup when coprocessor.UpdateProducers() is called the
# first time.
coprocessor = CreateCoProcessor()
#--------------------------------------------------------------
# Enable Live-Visualizaton with ParaView
coprocessor.EnableLiveVisualization(False)
# ---------------------- Data Selection method ----------------------
def RequestDataDescription(datadescription):
"Callback to populate the request for current timestep"
global coprocessor
if datadescription.GetForceOutput() == True or datadescription.GetTimeStep() % outputfrequency == 0:
# We are just going to request all fields and meshes from the simulation
# code/adaptor.
for i in range(datadescription.GetNumberOfInputDescriptions()):
datadescription.GetInputDescription(i).AllFieldsOn()
datadescription.GetInputDescription(i).GenerateMeshOn()
return
# setup requests for all inputs based on the requirements of the
# pipeline.
coprocessor.LoadRequestedData(datadescription)
# ------------------------ Processing method ------------------------
def DoCoProcessing(datadescription):
"Callback to do co-processing for current timestep"
global coprocessor
# Update the coprocessor by providing it the newly generated simulation data.
# If the pipeline hasn't been setup yet, this will setup the pipeline.
coprocessor.UpdateProducers(datadescription)
# Write output data, if appropriate.
coprocessor.WriteData(datadescription);

View File

@ -0,0 +1,77 @@
from paraview.simple import *
from paraview import coprocessing
# The frequency to output everything
outputfrequency = 5
# This is largely identical to the Catalyst allinputsgridwriter.py example
# but only handle vtkMultiBlockDataSet, since that is what we generate
# ----------------------- CoProcessor definition -----------------------
def CreateCoProcessor():
def _CreatePipeline(coprocessor, datadescription):
class Pipeline:
for i in range(datadescription.GetNumberOfInputDescriptions()):
name = datadescription.GetInputDescriptionName(i)
input = coprocessor.CreateProducer(datadescription, name)
grid = input.GetClientSideObject().GetOutputDataObject(0)
if grid.IsA('vtkMultiBlockDataSet'):
writer = servermanager.writers.XMLMultiBlockDataWriter(Input=input)
coprocessor.RegisterWriter(writer, filename=name+'_%t.vtm', freq=outputfrequency)
return Pipeline()
class CoProcessor(coprocessing.CoProcessor):
def CreatePipeline(self, datadescription):
self.Pipeline = _CreatePipeline(self, datadescription)
return CoProcessor()
#--------------------------------------------------------------
# Global variables that will hold the pipeline for each timestep
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
# It will be automatically setup when coprocessor.UpdateProducers() is called the
# first time.
coprocessor = CreateCoProcessor()
#--------------------------------------------------------------
# Enable Live-Visualizaton with ParaView
coprocessor.EnableLiveVisualization(False)
# ---------------------- Data Selection method ----------------------
def RequestDataDescription(datadescription):
"Callback to populate the request for current timestep"
global coprocessor
if datadescription.GetForceOutput() == True or datadescription.GetTimeStep() % outputfrequency == 0:
# We are just going to request all fields and meshes from the simulation
# code/adaptor.
for i in range(datadescription.GetNumberOfInputDescriptions()):
datadescription.GetInputDescription(i).AllFieldsOn()
datadescription.GetInputDescription(i).GenerateMeshOn()
return
# setup requests for all inputs based on the requirements of the
# pipeline.
coprocessor.LoadRequestedData(datadescription)
# ------------------------ Processing method ------------------------
def DoCoProcessing(datadescription):
"Callback to do co-processing for current timestep"
global coprocessor
# Update the coprocessor by providing it the newly generated simulation data.
# If the pipeline hasn't been setup yet, this will setup the pipeline.
coprocessor.UpdateProducers(datadescription)
# Write output data, if appropriate.
coprocessor.WriteData(datadescription);
# Write image capture (Last arg: rescale lookup table), if appropriate.
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
# Live Visualization, if enabled.
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)

View File

@ -0,0 +1,78 @@
from paraview.simple import *
from paraview import coprocessing
# The frequency to output everything
outputfrequency = 5
# As per writeAll, but only for "/mesh" sub-channels.
# ----------------------- CoProcessor definition -----------------------
def CreateCoProcessor():
def _CreatePipeline(coprocessor, datadescription):
class Pipeline:
for i in range(datadescription.GetNumberOfInputDescriptions()):
name = datadescription.GetInputDescriptionName(i)
if not name.endswith('/mesh'):
continue
input = coprocessor.CreateProducer(datadescription, name)
grid = input.GetClientSideObject().GetOutputDataObject(0)
if grid.IsA('vtkMultiBlockDataSet'):
writer = servermanager.writers.XMLMultiBlockDataWriter(Input=input)
coprocessor.RegisterWriter(writer, filename=name+'_%t.vtm', freq=outputfrequency)
return Pipeline()
class CoProcessor(coprocessing.CoProcessor):
def CreatePipeline(self, datadescription):
self.Pipeline = _CreatePipeline(self, datadescription)
return CoProcessor()
#--------------------------------------------------------------
# Global variables that will hold the pipeline for each timestep
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
# It will be automatically setup when coprocessor.UpdateProducers() is called the
# first time.
coprocessor = CreateCoProcessor()
#--------------------------------------------------------------
# Enable Live-Visualizaton with ParaView
coprocessor.EnableLiveVisualization(False)
# ---------------------- Data Selection method ----------------------
def RequestDataDescription(datadescription):
"Callback to populate the request for current timestep"
global coprocessor
if datadescription.GetForceOutput() == True or datadescription.GetTimeStep() % outputfrequency == 0:
# We are just going to request all fields and meshes from the simulation
# code/adaptor.
for i in range(datadescription.GetNumberOfInputDescriptions()):
datadescription.GetInputDescription(i).AllFieldsOn()
datadescription.GetInputDescription(i).GenerateMeshOn()
return
# setup requests for all inputs based on the requirements of the
# pipeline.
coprocessor.LoadRequestedData(datadescription)
# ------------------------ Processing method ------------------------
def DoCoProcessing(datadescription):
"Callback to do co-processing for current timestep"
global coprocessor
# Update the coprocessor by providing it the newly generated simulation data.
# If the pipeline hasn't been setup yet, this will setup the pipeline.
coprocessor.UpdateProducers(datadescription)
# Write output data, if appropriate.
coprocessor.WriteData(datadescription);
# Write image capture (Last arg: rescale lookup table), if appropriate.
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
# Live Visualization, if enabled.
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)

View File

@ -0,0 +1,78 @@
from paraview.simple import *
from paraview import coprocessing
# The frequency to output everything
outputfrequency = 5
# As per writeAll, but only for "/patches" sub-channels.
# ----------------------- CoProcessor definition -----------------------
def CreateCoProcessor():
def _CreatePipeline(coprocessor, datadescription):
class Pipeline:
for i in range(datadescription.GetNumberOfInputDescriptions()):
name = datadescription.GetInputDescriptionName(i)
if not name.endswith('/patches'):
continue
input = coprocessor.CreateProducer(datadescription, name)
grid = input.GetClientSideObject().GetOutputDataObject(0)
if grid.IsA('vtkMultiBlockDataSet'):
writer = servermanager.writers.XMLMultiBlockDataWriter(Input=input)
coprocessor.RegisterWriter(writer, filename=name+'_%t.vtm', freq=outputfrequency)
return Pipeline()
class CoProcessor(coprocessing.CoProcessor):
def CreatePipeline(self, datadescription):
self.Pipeline = _CreatePipeline(self, datadescription)
return CoProcessor()
#--------------------------------------------------------------
# Global variables that will hold the pipeline for each timestep
# Creating the CoProcessor object, doesn't actually create the ParaView pipeline.
# It will be automatically setup when coprocessor.UpdateProducers() is called the
# first time.
coprocessor = CreateCoProcessor()
#--------------------------------------------------------------
# Enable Live-Visualizaton with ParaView
coprocessor.EnableLiveVisualization(False)
# ---------------------- Data Selection method ----------------------
def RequestDataDescription(datadescription):
"Callback to populate the request for current timestep"
global coprocessor
if datadescription.GetForceOutput() == True or datadescription.GetTimeStep() % outputfrequency == 0:
# We are just going to request all fields and meshes from the simulation
# code/adaptor.
for i in range(datadescription.GetNumberOfInputDescriptions()):
datadescription.GetInputDescription(i).AllFieldsOn()
datadescription.GetInputDescription(i).GenerateMeshOn()
return
# setup requests for all inputs based on the requirements of the
# pipeline.
coprocessor.LoadRequestedData(datadescription)
# ------------------------ Processing method ------------------------
def DoCoProcessing(datadescription):
"Callback to do co-processing for current timestep"
global coprocessor
# Update the coprocessor by providing it the newly generated simulation data.
# If the pipeline hasn't been setup yet, this will setup the pipeline.
coprocessor.UpdateProducers(datadescription)
# Write output data, if appropriate.
coprocessor.WriteData(datadescription);
# Write image capture (Last arg: rescale lookup table), if appropriate.
coprocessor.WriteImages(datadescription, rescale_lookuptable=False)
# Live Visualization, if enabled.
coprocessor.DoLiveVisualization(datadescription, "localhost", 22222)

View File

@ -13,8 +13,8 @@
# config.csh/example/paraview
#
# Description
# Example of defining a different ParaView_VERSION but retaining
# the standard config.csh/paraview mechanism
# Example of defining a different ParaView_VERSION but retaining the
# standard config.csh/paraview mechanism
#
# Note
# This file could be copied to a user or site location, but should never
@ -25,7 +25,8 @@
set pv=5.5.0
set pv=5.5.0-mpipy
set qt=qt-5.9.0
eval `foamEtcFile -csh -config -mode=o paraview -- ParaView_VERSION=$pv`
eval `foamEtcFile -csh -config -mode=o paraview -- ParaView_VERSION=$pv ParaView_QT=$qt`
#------------------------------------------------------------------------------

View File

@ -120,8 +120,16 @@ if ( $?ParaView_VERSION ) then
#OBSOLETE? endif
# QT libraries as required
# Set Qt5_DIR to root directory.
# Another possibility: "qtpaths --qt-version"
set qtDir="$archDir/$ParaView_QT"
if ( -d "$qtDir" ) then
switch ($ParaView_QT)
case *-qt*:
setenv Qt5_DIR $qtDir
breaksw
endsw
foreach qtLibDir ("$qtDir/lib$WM_COMPILER_LIB_ARCH" "$qtDir/lib")
if ( -d "$qtLibDir" ) then
setenv LD_LIBRARY_PATH "${qtLibDir}:${LD_LIBRARY_PATH}"

View File

@ -111,6 +111,7 @@ unsetenv ParaView_INCLUDE_DIR
unsetenv ParaView_VERSION
unsetenv PV_PLUGIN_PATH
unsetenv VTK_DIR
unsetenv Qt5_DIR # Perhaps only unset if it is in WM_THIRD_PARTY_DIR?
#------------------------------------------------------------------------------
# Unset other ThirdParty environment variables

View File

@ -13,8 +13,8 @@
# config.sh/example/paraview
#
# Description
# Example of defining a different ParaView_VERSION but retaining
# the standard config.sh/paraview mechanism
# Example of defining a different ParaView_VERSION but retaining the
# standard config.sh/paraview mechanism
#
# Note
# This file could be copied to a user or site location, but should never
@ -25,7 +25,8 @@
pv=5.5.0
pv=5.5.0-mpipy
qt=qt-5.9.0
eval $(foamEtcFile -sh -config -mode=o paraview -- ParaView_VERSION=$pv)
eval $(foamEtcFile -sh -config -mode=o paraview -- ParaView_VERSION=$pv ParaView_QT=$qt)
#------------------------------------------------------------------------------

View File

@ -127,10 +127,16 @@ then
#OBSOLETE? export PYTHONPATH=$PYTHONPATH:${PYTHONPATH:+:}$pvPython:$pvLibDir
#OBSOLETE? fi
# QT libraries as required
# QT libraries as required, and Qt5_DIR for the root directory.
# Another possibility: "qtpaths --qt-version"
qtDir="$archDir/$ParaView_QT"
if [ -d "$qtDir" ]
then
case "$ParaView_QT" in
*-5*)
export Qt5_DIR=$qtDir
;;
esac
for qtLibDir in $qtDir/lib$WM_COMPILER_LIB_ARCH $qtDir/lib
do
if [ -d "$qtLibDir" ]

View File

@ -97,7 +97,6 @@ then
unset OPAL_PREFIX
fi
#------------------------------------------------------------------------------
# Unset Ensight/ParaView-related environment variables
@ -108,6 +107,12 @@ unset ParaView_VERSION
unset PV_PLUGIN_PATH
unset VTK_DIR
# Undefine Qt5_DIR if set to one of the paths on foamOldDirs
if [ -z "$($foamClean -env=Qt5_DIR "$foamOldDirs")" ]
then
unset Qt5_DIR
fi
#------------------------------------------------------------------------------
# Unset other ThirdParty environment variables

View File

@ -39,8 +39,8 @@ InfoSwitches
writeDictionaries 0;
writeOptionalEntries 0;
// Write lagrangian "positions" file in v1706 format (at earlier)
writeLagrangianPositions 0;
// Write lagrangian "positions" file in v1706 format (and earlier)
writeLagrangianPositions 1;
// Report hosts used (parallel)
// - 0 = none

View File

@ -489,6 +489,10 @@ mode_t Foam::mode(const fileName& name, const bool followLink)
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : name:" << name << endl;
if ((POSIX::debug & 2) && !Pstream::master())
{
error::printStack(Pout);
}
}
// Ignore an empty name => always 0
@ -516,10 +520,6 @@ Foam::fileName::Type Foam::type(const fileName& name, const bool followLink)
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : name:" << name << endl;
if ((POSIX::debug & 2) && !Pstream::master())
{
error::printStack(Pout);
}
}
mode_t m = mode(name, followLink);
@ -1678,142 +1678,4 @@ Foam::fileNameList Foam::dlLoaded()
}
static Foam::DynamicList<Foam::autoPtr<pthread_t>> threads_;
static Foam::DynamicList<Foam::autoPtr<pthread_mutex_t>> mutexes_;
Foam::label Foam::allocateThread()
{
forAll(threads_, i)
{
if (!threads_[i].valid())
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : reusing index:" << i << endl;
}
// Reuse entry
threads_[i].reset(new pthread_t());
return i;
}
}
const label index = threads_.size();
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : new index:" << index << endl;
}
threads_.append(autoPtr<pthread_t>(new pthread_t()));
return index;
}
void Foam::createThread
(
const label index,
void *(*start_routine) (void *),
void *arg
)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
if (pthread_create(&threads_[index](), nullptr, start_routine, arg))
{
FatalErrorInFunction
<< "Failed starting thread " << index << exit(FatalError);
}
}
void Foam::joinThread(const label index)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
if (pthread_join(threads_[index](), nullptr))
{
FatalErrorInFunction << "Failed joining thread " << index
<< exit(FatalError);
}
}
void Foam::freeThread(const label index)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
threads_[index].clear();
}
Foam::label Foam::allocateMutex()
{
forAll(mutexes_, i)
{
if (!mutexes_[i].valid())
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : reusing index:" << i << endl;
}
// Reuse entry
mutexes_[i].reset(new pthread_mutex_t());
return i;
}
}
const label index = mutexes_.size();
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : new index:" << index << endl;
}
mutexes_.append(autoPtr<pthread_mutex_t>(new pthread_mutex_t()));
return index;
}
void Foam::lockMutex(const label index)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
if (pthread_mutex_lock(&mutexes_[index]()))
{
FatalErrorInFunction << "Failed locking mutex " << index
<< exit(FatalError);
}
}
void Foam::unlockMutex(const label index)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
if (pthread_mutex_unlock(&mutexes_[index]()))
{
FatalErrorInFunction << "Failed unlocking mutex " << index
<< exit(FatalError);
}
}
void Foam::freeMutex(const label index)
{
if (POSIX::debug)
{
Pout<< FUNCTION_NAME << " : index:" << index << endl;
}
mutexes_[index].clear();
}
// ************************************************************************* //

View File

@ -11,9 +11,11 @@ global/etcFiles/etcFiles.C
fileOps = global/fileOperations
$(fileOps)/fileOperation/fileOperation.C
$(fileOps)/fileOperationInitialise/fileOperationInitialise.C
$(fileOps)/uncollatedFileOperation/uncollatedFileOperation.C
$(fileOps)/masterUncollatedFileOperation/masterUncollatedFileOperation.C
$(fileOps)/collatedFileOperation/collatedFileOperation.C
$(fileOps)/collatedFileOperation/hostCollatedFileOperation.C
$(fileOps)/collatedFileOperation/threadedCollatedOFstream.C
$(fileOps)/collatedFileOperation/OFstreamCollator.C
@ -288,7 +290,6 @@ $(Time)/TimeIO.C
$(Time)/findTimes.C
$(Time)/subCycleTime.C
$(Time)/subLoopTime.C
$(Time)/findInstance.C
$(Time)/timeSelector.C
$(Time)/instant/instant.C

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -681,14 +681,15 @@ void Foam::decomposedBlockData::gather
List<int> recvOffsets;
List<int> recvSizes;
if (UPstream::master())
if (UPstream::master(comm))
{
recvOffsets.setSize(nProcs);
forAll(recvOffsets, proci)
{
// Note: truncating long int to int since UPstream::gather limited
// to ints
recvOffsets[proci] =
reinterpret_cast<char*>(&datas[proci])
- data0Ptr;
int(reinterpret_cast<char*>(&datas[proci]) - data0Ptr);
}
recvSizes.setSize(nProcs, sizeof(label));
}
@ -748,7 +749,8 @@ void Foam::decomposedBlockData::gatherSlaveData
&& (UPstream::myProcNo(comm) < startProc+nProcs)
)
{
nSend = data.byteSize();
// Note: UPstream::gather limited to int
nSend = int(data.byteSize());
}
UPstream::gather
@ -764,6 +766,46 @@ void Foam::decomposedBlockData::gatherSlaveData
}
Foam::label Foam::decomposedBlockData::calcNumProcs
(
const label comm,
const off_t maxBufferSize,
const labelUList& recvSizes,
const label startProci
)
{
const label nProcs = UPstream::nProcs(comm);
label nSendProcs = -1;
if (UPstream::master(comm))
{
off_t totalSize = recvSizes[startProci];
label proci = startProci+1;
while (proci < nProcs && (totalSize+recvSizes[proci] < maxBufferSize))
{
totalSize += recvSizes[proci];
proci++;
}
nSendProcs = proci-startProci;
}
// Scatter nSendProcs
label n;
UPstream::scatter
(
reinterpret_cast<const char*>(&nSendProcs),
List<int>(nProcs, sizeof(nSendProcs)),
List<int>(nProcs, 0),
reinterpret_cast<char*>(&n),
sizeof(n),
comm
);
return n;
}
bool Foam::decomposedBlockData::writeBlocks
(
const label comm,
@ -772,8 +814,7 @@ bool Foam::decomposedBlockData::writeBlocks
const UList<char>& data,
const labelUList& recvSizes,
const bool haveSlaveData,
const List<char>& slaveData,
const PtrList<SubList<char>>& slaveData,
const UPstream::commsTypes commsType,
const bool syncReturnState
@ -784,17 +825,15 @@ bool Foam::decomposedBlockData::writeBlocks
Pout<< "decomposedBlockData::writeBlocks:"
<< " stream:" << (osPtr.valid() ? osPtr().name() : "invalid")
<< " data:" << data.size()
<< " haveSlaveData:" << haveSlaveData
<< " (master only) slaveData:" << slaveData.size()
<< " commsType:" << Pstream::commsTypeNames[commsType] << endl;
}
const label nProcs = UPstream::nProcs(comm);
bool ok = true;
if (haveSlaveData)
if (slaveData.size())
{
// Already have gathered the slave data. communicator only used to
// check who is the master
@ -821,8 +860,7 @@ bool Foam::decomposedBlockData::writeBlocks
os << nl << nl << "// Processor" << proci << nl;
start[proci] = os.stdStream().tellp();
os << SubList<char>(slaveData, recvSizes[proci], slaveOffset);
os << slaveData[proci];
slaveOffset += recvSizes[proci];
}
@ -897,44 +935,24 @@ bool Foam::decomposedBlockData::writeBlocks
// maxMasterFileBufferSize
// Starting slave processor and number of processors
labelPair startAndSize(1, nProcs-1);
label startProc = 1;
label nSendProcs = nProcs-1;
while (startAndSize[1] > 0)
while (nSendProcs > 0)
{
labelPair masterData(startAndSize);
if (UPstream::master(comm))
{
label totalSize = recvSizes[masterData[0]];
label proci = masterData[0]+1;
while
(
proci < nProcs
&& (
totalSize+recvSizes[proci]
< fileOperations::masterUncollatedFileOperation::
maxMasterFileBufferSize
)
)
{
totalSize += recvSizes[proci];
++proci;
}
masterData[1] = proci-masterData[0];
}
// Scatter masterData
UPstream::scatter
nSendProcs = calcNumProcs
(
reinterpret_cast<const char*>(masterData.cdata()),
List<int>(nProcs, sizeof(masterData)),
List<int>(nProcs, 0),
reinterpret_cast<char*>(startAndSize.data()),
sizeof(startAndSize),
comm
comm,
off_t
(
fileOperations::masterUncollatedFileOperation::
maxMasterFileBufferSize
),
recvSizes,
startProc
);
if (startAndSize[0] == nProcs || startAndSize[1] == 0)
if (startProc == nProcs || nSendProcs == 0)
{
break;
}
@ -949,8 +967,8 @@ bool Foam::decomposedBlockData::writeBlocks
data,
recvSizes,
startAndSize[0], // startProc,
startAndSize[1], // nProcs,
startProc, // startProc,
nSendProcs, // nProcs,
sliceOffsets,
recvData
@ -963,9 +981,9 @@ bool Foam::decomposedBlockData::writeBlocks
// Write slaves
for
(
label proci = startAndSize[0];
proci < startAndSize[0]+startAndSize[1];
++proci
label proci = startProc;
proci < startProc+nSendProcs;
proci++
)
{
os << nl << nl << "// Processor" << proci << nl;
@ -981,7 +999,7 @@ bool Foam::decomposedBlockData::writeBlocks
}
}
startAndSize[0] += startAndSize[1];
startProc += nSendProcs;
}
if (UPstream::master(comm))
@ -1027,7 +1045,7 @@ bool Foam::decomposedBlockData::writeData(Ostream& os) const
);
IOobject io(*this);
if (Pstream::master())
if (Pstream::master(comm_))
{
IStringStream is
(
@ -1043,7 +1061,7 @@ bool Foam::decomposedBlockData::writeData(Ostream& os) const
// version
string versionString(os.version().str());
Pstream::scatter(versionString);
Pstream::scatter(versionString, Pstream::msgType(), comm_);
// stream
string formatString;
@ -1051,21 +1069,21 @@ bool Foam::decomposedBlockData::writeData(Ostream& os) const
OStringStream os;
os << os.format();
formatString = os.str();
Pstream::scatter(formatString);
Pstream::scatter(formatString, Pstream::msgType(), comm_);
}
//word masterName(name());
//Pstream::scatter(masterName);
//Pstream::scatter(masterName, Pstream::msgType(), comm_);
Pstream::scatter(io.headerClassName());
Pstream::scatter(io.note());
Pstream::scatter(io.headerClassName(), Pstream::msgType(), comm_);
Pstream::scatter(io.note(), Pstream::msgType(), comm_);
//Pstream::scatter(io.instance(), Pstream::msgType(), comm);
//Pstream::scatter(io.local(), Pstream::msgType(), comm);
fileName masterLocation(instance()/db().dbDir()/local());
Pstream::scatter(masterLocation);
Pstream::scatter(masterLocation, Pstream::msgType(), comm_);
if (!Pstream::master())
if (!Pstream::master(comm_))
{
writeHeader
(
@ -1081,7 +1099,7 @@ bool Foam::decomposedBlockData::writeData(Ostream& os) const
os.writeQuoted(str, false);
if (!Pstream::master())
if (!Pstream::master(comm_))
{
IOobject::writeEndDivider(os);
}
@ -1108,10 +1126,10 @@ bool Foam::decomposedBlockData::writeObject
}
labelList recvSizes;
gather(comm_, this->byteSize(), recvSizes);
gather(comm_, label(this->byteSize()), recvSizes);
List<std::streamoff> start;
List<char> slaveData; // dummy already received slave data
PtrList<SubList<char>> slaveData; // dummy slave data
return writeBlocks
(
comm_,
@ -1119,7 +1137,6 @@ bool Foam::decomposedBlockData::writeObject
start,
*this,
recvSizes,
false, // don't have slave data
slaveData,
commsType_
);

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -66,6 +66,16 @@ protected:
// Protected member functions
//- Helper: determine number of processors whose recvSizes fits
// ito maxBufferSize
static label calcNumProcs
(
const label comm,
const off_t maxBufferSize,
const labelUList& recvSizes,
const label startProci
);
//- Read data into *this. ISstream is only valid on master.
static bool readBlocks
(
@ -202,12 +212,12 @@ public:
const label comm,
autoPtr<OSstream>& osPtr,
List<std::streamoff>& start,
const UList<char>&,
const UList<char>& masterData,
const labelUList& recvSizes,
const bool haveSlaveData, // does master have slaveData
const List<char>& slaveData, // optional slave data (on master)
// optional slave data (on master)
const PtrList<SubList<char>>& slaveData,
const UPstream::commsTypes,
const bool syncReturnState = true

View File

@ -372,10 +372,8 @@ public:
static void addValidParOptions(HashTable<string>& validParOptions);
//- Initialisation function called from main
// Spawns slave processes and initialises inter-communication.
// \note warns if MPI has already been initialized.
// Fatal if MPI has already been finalized.
static bool init(int& argc, char**& argv);
// Spawns slave processes and initialises inter-communication
static bool init(int& argc, char**& argv, const bool needsThread);
//- Special purpose initialisation function.
// Performs a basic MPI_Init without any other setup.

View File

@ -714,6 +714,36 @@ Foam::instantList Foam::Time::times() const
}
Foam::word Foam::Time::findInstance
(
const fileName& dir,
const word& name,
const IOobject::readOption rOpt,
const word& stopInstance
) const
{
IOobject startIO
(
name, // name might be empty!
timeName(),
dir,
*this,
rOpt
);
IOobject io
(
fileHandler().findInstance
(
startIO,
timeOutputValue(),
stopInstance
)
);
return io.instance();
}
Foam::word Foam::Time::findInstancePath
(
const fileName& directory,

View File

@ -196,9 +196,6 @@ protected:
//- Read the control dictionary and set the write controls etc.
virtual void readDict();
//- Find IOobject in the objectPath
static bool exists(IOobject& io);
private:

View File

@ -1,236 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 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 <http://www.gnu.org/licenses/>.
Description
If "name" is empty: return the location of "directory"
If "name" is not empty: return the location of "directory" containing the
file "name".
Used in reading mesh data.
\*---------------------------------------------------------------------------*/
#include "Time.H"
#include "IOobject.H"
#include "IOList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
bool Foam::Time::exists(IOobject& io)
{
// Generate filename for object
fileName objPath(fileHandler().objectPath(io, word::null));
// Test for either directory or a (valid) file & IOobject
bool ok;
if (io.name().empty())
{
ok = fileHandler().isDir(objPath);
}
else
{
ok =
fileHandler().isFile(objPath)
&& io.typeHeaderOk<IOList<label>>(false);// object with local scope
}
if (!ok)
{
// Re-test with raw objectPath. This is for backwards
// compatibility
fileName originalPath(io.objectPath());
if (originalPath != objPath)
{
// Test for either directory or a (valid) file & IOobject
if (io.name().empty())
{
ok = fileHandler().isDir(originalPath);
}
else
{
ok =
fileHandler().isFile(originalPath)
&& io.typeHeaderOk<IOList<label>>(false);
}
}
}
return ok;
}
Foam::word Foam::Time::findInstance
(
const fileName& dir,
const word& name,
const IOobject::readOption rOpt,
const word& stopInstance
) const
{
// Note: - if name is empty, just check the directory itself
// - check both for isFile and headerOk since the latter does a
// filePath so searches for the file.
// - check for an object with local file scope (so no looking up in
// parent directory in case of parallel)
{
IOobject io
(
name, // name might be empty!
timeName(),
dir,
*this
);
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found exact match for \"" << name
<< "\" in " << timeName()/dir
<< endl;
}
return timeName();
}
}
// Search back through the time directories to find the time
// closest to and lower than current time
instantList ts = times();
label instanceI;
for (instanceI = ts.size()-1; instanceI >= 0; --instanceI)
{
if (ts[instanceI].value() <= timeOutputValue())
{
break;
}
}
// continue searching from here
for (; instanceI >= 0; --instanceI)
{
IOobject io
(
name, // name might be empty!
ts[instanceI].name(),
dir,
*this
);
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found instance match for \"" << name
<< "\" in " << ts[instanceI].name()/dir
<< endl;
}
return ts[instanceI].name();
}
// Check if hit minimum instance
if (ts[instanceI].name() == stopInstance)
{
if (debug)
{
//InfoInFunction
Pout<< "findInstance : "
<< "Hit stopInstance " << stopInstance
<< endl;
}
if
(
rOpt == IOobject::MUST_READ
|| rOpt == IOobject::MUST_READ_IF_MODIFIED
)
{
if (name.empty())
{
FatalErrorInFunction
<< "Cannot find directory "
<< dir << " in times " << timeName()
<< " down to " << stopInstance
<< exit(FatalError);
}
else
{
FatalErrorInFunction
<< "Cannot find file \"" << name << "\" in directory "
<< dir << " in times " << timeName()
<< " down to " << stopInstance
<< exit(FatalError);
}
}
return ts[instanceI].name();
}
}
// not in any of the time directories, try constant
// Note. This needs to be a hard-coded constant, rather than the
// constant function of the time, because the latter points to
// the case constant directory in parallel cases
IOobject io
(
name,
constant(),
dir,
*this
);
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found constant match for \"" << name
<< "\" in " << constant()/dir
<< endl;
}
return constant();
}
if (rOpt == IOobject::MUST_READ || rOpt == IOobject::MUST_READ_IF_MODIFIED)
{
FatalErrorInFunction
<< "Cannot find file \"" << name << "\" in directory "
<< dir << " in times " << timeName()
<< " down to " << constant()
<< exit(FatalError);
}
return constant();
}
// ************************************************************************* //

View File

@ -236,7 +236,7 @@ void Foam::error::exit(const int errNo)
{
Perr<< endl << *this << endl
<< "\nFOAM exiting\n" << endl;
::exit(1);
::exit(errNo);
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015-2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -183,7 +183,8 @@ void Foam::regIOobject::close()
if (IFstream::debug)
{
Pout<< "regIOobject::close() : "
<< "finished reading " << isPtr_().name()
<< "finished reading "
<< (isPtr_.valid() ? isPtr_().name() : "dummy")
<< endl;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2013 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2013-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -54,7 +54,7 @@ public:
// Constructors
//- Construct given addressing
patchFieldSubset(const labelUList& directAddressing)
directFieldMapper(const labelUList& directAddressing)
:
directAddressing_(directAddressing),
hasUnmapped_(false)

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -86,6 +86,7 @@ void pow
gf.oriented() = pow(gf1.oriented(), r);
}
template
<
class Type,
@ -181,6 +182,7 @@ void sqr
gf.oriented() = sqr(gf1.oriented());
}
template<class Type, template<class> class PatchField, class GeoMesh>
tmp
<
@ -217,6 +219,7 @@ sqr(const GeometricField<Type, PatchField, GeoMesh>& gf)
return tSqr;
}
template<class Type, template<class> class PatchField, class GeoMesh>
tmp
<
@ -270,6 +273,7 @@ void magSqr
gsf.oriented() = magSqr(gf.oriented());
}
template<class Type, template<class> class PatchField, class GeoMesh>
tmp<GeometricField<scalar, PatchField, GeoMesh>> magSqr
(
@ -343,6 +347,7 @@ void mag
gsf.oriented() = mag(gf.oriented());
}
template<class Type, template<class> class PatchField, class GeoMesh>
tmp<GeometricField<scalar, PatchField, GeoMesh>> mag
(
@ -458,6 +463,7 @@ cmptAv(const GeometricField<Type, PatchField, GeoMesh>& gf)
return CmptAv;
}
template<class Type, template<class> class PatchField, class GeoMesh>
tmp
<
@ -500,7 +506,7 @@ cmptAv(const tmp<GeometricField<Type, PatchField, GeoMesh>>& tgf)
}
#define UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(returnType, func, gFunc) \
#define UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(returnType, func, binaryOp) \
\
template<class Type, template<class> class PatchField, class GeoMesh> \
dimensioned<returnType> func \
@ -512,7 +518,15 @@ dimensioned<returnType> func \
( \
#func "(" + gf.name() + ')', \
gf.dimensions(), \
Foam::func(gFunc(gf.primitiveField()), gFunc(gf.boundaryField())) \
returnReduce \
( \
Foam::func \
( \
Foam::func(gf.primitiveField()), \
Foam::func(gf.boundaryField()) \
), \
binaryOp<Type>() \
) \
); \
} \
\
@ -527,8 +541,8 @@ dimensioned<returnType> func \
return res; \
}
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, gMax)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, gMin)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, maxOp)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, minOp)
#undef UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -212,7 +212,7 @@ tmp
cmptAv(const tmp<GeometricField<Type, PatchField, GeoMesh>>& tgf);
#define UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(returnType, func, gFunc) \
#define UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(returnType, func, binaryOp) \
\
template<class Type, template<class> class PatchField, class GeoMesh> \
dimensioned<returnType> func \
@ -226,8 +226,8 @@ dimensioned<returnType> func \
const tmp<GeometricField<Type, PatchField, GeoMesh>>& tgf1 \
);
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, gMax)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, gMin)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, maxOp)
UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, minOp)
#undef UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY

View File

@ -40,8 +40,9 @@ License
#include "foamVersion.H"
#include "stringOps.H"
#include "CStringList.H"
#include "uncollatedFileOperation.H"
#include "masterUncollatedFileOperation.H"
#include "stringListOps.H"
#include "fileOperation.H"
#include "fileOperationInitialise.H"
#include "IOmanip.H"
#include <cctype>
@ -83,6 +84,12 @@ Foam::argList::initValidTables::initValidTables()
"decomposeParDict", "file",
"read decomposePar dictionary from specified location"
);
argList::addOption
(
"hostRoots", "(((host1 dir1) .. (hostN dirN))",
"slave root directories (per host) for distributed running"
);
validParOptions.set("hostRoots", "((host1 dir1) .. (hostN dirN))");
argList::addBoolOption
(
@ -324,6 +331,7 @@ void Foam::argList::noParallel()
removeOption("parallel");
removeOption("roots");
removeOption("decomposeParDict");
removeOption("hostRoots");
validParOptions.clear();
}
@ -687,6 +695,34 @@ Foam::argList::argList
options_(argc),
distributed_(false)
{
// Check for fileHandler
word handlerType(getEnv("FOAM_FILEHANDLER"));
for (int argI = 0; argI < argc; ++argI)
{
if (argv[argI][0] == '-')
{
const char *optionName = &argv[argI][1];
if (string(optionName) == "fileHandler")
{
handlerType = argv[argI+1];
break;
}
}
}
if (handlerType.empty())
{
handlerType = fileOperation::defaultFileHandler;
}
// Detect any parallel options
bool needsThread = fileOperations::fileOperationInitialise::New
(
handlerType,
argc,
argv
)().needsThreading();
// Check if this run is a parallel run by searching for any parallel option
// If found call runPar which might filter argv
for (int argi = 1; argi < argc; ++argi)
@ -697,7 +733,7 @@ Foam::argList::argList
if (validParOptions.found(optName))
{
parRunControl_.runPar(argc, argv);
parRunControl_.runPar(argc, argv, needsThread);
break;
}
}
@ -942,6 +978,58 @@ void Foam::argList::parse
Foam::fileHandler(handler);
}
stringList slaveProcs;
stringList slaveMachine;
const int writeHostsSwitch = debug::infoSwitch("writeHosts", 1);
// Collect slave machine/pid, and check that the build is identical
if (parRunControl_.parRun())
{
if (Pstream::master())
{
slaveProcs.setSize(Pstream::nProcs() - 1);
slaveMachine.setSize(Pstream::nProcs() - 1);
label proci = 0;
for
(
int slave = Pstream::firstSlave();
slave <= Pstream::lastSlave();
slave++
)
{
IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
string slaveBuild;
label slavePid;
fromSlave >> slaveBuild >> slaveMachine[proci] >> slavePid;
slaveProcs[proci] = slaveMachine[proci] + "." + name(slavePid);
proci++;
// Check build string to make sure all processors are running
// the same build
if (slaveBuild != Foam::FOAMbuild)
{
FatalErrorIn(executable())
<< "Master is running version " << Foam::FOAMbuild
<< "; slave " << proci << " is running version "
<< slaveBuild
<< exit(FatalError);
}
}
}
else
{
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster << string(Foam::FOAMbuild) << hostName() << pid();
}
}
// Case is a single processor run unless it is running parallel
int nProcs = 1;
@ -999,6 +1087,52 @@ void Foam::argList::parse
dictNProcs = roots.size()+1;
}
}
else if (options_.found("hostRoots"))
{
source = "-hostRoots";
IStringStream is(options_["hostRoots"]);
List<Tuple2<wordRe, fileName>> hostRoots(is);
roots.setSize(Pstream::nProcs()-1);
forAll(hostRoots, i)
{
const Tuple2<wordRe, fileName>& hostRoot = hostRoots[i];
const wordRe& re = hostRoot.first();
labelList matchedRoots(findStrings(re, slaveMachine));
forAll(matchedRoots, matchi)
{
label slavei = matchedRoots[matchi];
if (roots[slavei] != wordRe())
{
FatalErrorInFunction
<< "Slave " << slaveMachine[slavei]
<< " has multiple matching roots in "
<< hostRoots << exit(FatalError);
}
else
{
roots[slavei] = hostRoot.second();
}
}
}
// Check
forAll(roots, slavei)
{
if (roots[slavei] == wordRe())
{
FatalErrorInFunction
<< "Slave " << slaveMachine[slavei]
<< " has no matching roots in "
<< hostRoots << exit(FatalError);
}
}
if (roots.size() != 1)
{
dictNProcs = roots.size()+1;
}
}
else if (checkProcessorDirectories_)
{
// Use values from decomposeParDict, the location was already
@ -1172,55 +1306,6 @@ void Foam::argList::parse
case_ = globalCase_;
}
stringList slaveProcs;
const int writeHostsSwitch = debug::infoSwitch("writeHosts", 1);
// Collect slave machine/pid, and check that the build is identical
if (parRunControl_.parRun())
{
if (Pstream::master())
{
slaveProcs.setSize(Pstream::nProcs() - 1);
label proci = 0;
for
(
int slave = Pstream::firstSlave();
slave <= Pstream::lastSlave();
slave++
)
{
IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
string slaveBuild;
string slaveMachine;
label slavePid;
fromSlave >> slaveBuild >> slaveMachine >> slavePid;
slaveProcs[proci++] = slaveMachine + "." + name(slavePid);
// Check build string to make sure all processors are running
// the same build
if (slaveBuild != Foam::FOAMbuild)
{
FatalErrorIn(executable())
<< "Master is running version " << Foam::FOAMbuild
<< "; slave " << proci << " is running version "
<< slaveBuild
<< exit(FatalError);
}
}
}
else
{
OPstream toMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
toMaster << string(Foam::FOAMbuild) << hostName() << pid();
}
}
// Keep or discard slave and root information for reporting:
if (Pstream::master() && parRunControl_.parRun())
{
@ -1412,6 +1497,7 @@ bool Foam::argList::unsetOption(const word& optName)
optName == "case"
|| optName == "parallel"
|| optName == "roots"
|| optName == "hostRoots"
)
{
FatalErrorInFunction

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -70,11 +70,11 @@ public:
}
//- Initialize Pstream for a parallel run
void runPar(int& argc, char**& argv)
void runPar(int& argc, char**& argv, const bool needsThread)
{
RunPar = true;
if (!Pstream::init(argc, argv))
if (!Pstream::init(argc, argv, needsThread))
{
Info<< "Failed to start parallel run" << endl;
Pstream::exit(1);

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -95,21 +95,31 @@ Foam::dictionary& Foam::debug::controlDict()
{
if (!controlDictPtr_)
{
fileNameList controlDictFiles = findEtcFiles("controlDict", true);
controlDictPtr_ = new dictionary();
forAllReverse(controlDictFiles, cdfi)
string controlDictString(getEnv("FOAM_CONTROLDICT"));
if (!controlDictString.empty())
{
IFstream ifs(controlDictFiles[cdfi]);
if (!ifs.good())
// Read from environment
IStringStream is(controlDictString);
controlDictPtr_ = new dictionary(is);
}
else
{
fileNameList controlDictFiles = findEtcFiles("controlDict", true);
controlDictPtr_ = new dictionary();
forAllReverse(controlDictFiles, cdfi)
{
SafeFatalIOErrorInFunction
(
ifs,
"Cannot open controlDict"
);
IFstream ifs(controlDictFiles[cdfi]);
if (!ifs.good())
{
SafeFatalIOErrorInFunction
(
ifs,
"Cannot open controlDict"
);
}
controlDictPtr_->merge(dictionary(ifs));
}
controlDictPtr_->merge(dictionary(ifs));
}
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -26,6 +26,7 @@ License
#include "OFstreamCollator.H"
#include "OFstream.H"
#include "decomposedBlockData.H"
#include "masterUncollatedFileOperation.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -44,8 +45,7 @@ bool Foam::OFstreamCollator::writeFile
const fileName& fName,
const string& masterData,
const labelUList& recvSizes,
const bool haveSlaveData, // does master have slaveData
const UList<char>& slaveData, // on master: slave data
const PtrList<SubList<char>>& slaveData, // optional slave data
IOstream::streamFormat fmt,
IOstream::versionNumber ver,
IOstream::compressionType cmp,
@ -54,9 +54,22 @@ bool Foam::OFstreamCollator::writeFile
{
if (debug)
{
Pout<< "OFstreamCollator : Writing " << masterData.size()
Pout<< "OFstreamCollator : Writing master " << masterData.size()
<< " bytes to " << fName
<< " using comm " << comm << endl;
if (slaveData.size())
{
Pout<< "OFstreamCollator : Slave data" << endl;
forAll(slaveData, proci)
{
if (slaveData.set(proci))
{
Pout<< " " << proci
<< " size:" << slaveData[proci].size()
<< endl;
}
}
}
}
autoPtr<OSstream> osPtr;
@ -76,17 +89,20 @@ bool Foam::OFstreamCollator::writeFile
);
// We don't have IOobject so cannot use IOobject::writeHeader
OSstream& os = osPtr();
decomposedBlockData::writeHeader
(
os,
ver,
fmt,
typeName,
"",
fName,
fName.name()
);
if (!append)
{
OSstream& os = osPtr();
decomposedBlockData::writeHeader
(
os,
ver,
fmt,
typeName,
"",
fName,
fName.name()
);
}
}
@ -109,9 +125,13 @@ bool Foam::OFstreamCollator::writeFile
start,
slice,
recvSizes,
haveSlaveData,
slaveData,
UPstream::commsTypes::nonBlocking, //scheduled,
(
fileOperations::masterUncollatedFileOperation::
maxMasterFileBufferSize == 0
? UPstream::commsTypes::scheduled
: UPstream::commsTypes::nonBlocking
),
false // do not reduce return state
);
@ -132,7 +152,11 @@ bool Foam::OFstreamCollator::writeFile
{
sum += recvSizes[i];
}
Pout<< " (overall " << sum << ")";
// Use ostringstream to display long int (until writing these is
// supported)
std::ostringstream os;
os << sum;
Pout<< " (overall " << os.str() << ")";
}
Pout<< " to " << fName
<< " using comm " << comm << endl;
@ -151,12 +175,13 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
{
writeData* ptr = nullptr;
lockMutex(handler.mutex_);
if (handler.objects_.size())
{
ptr = handler.objects_.pop();
std::lock_guard<std::mutex> guard(handler.mutex_);
if (handler.objects_.size())
{
ptr = handler.objects_.pop();
}
}
unlockMutex(handler.mutex_);
if (!ptr)
{
@ -164,6 +189,28 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
}
else
{
// Convert storage to pointers
PtrList<SubList<char>> slaveData;
if (ptr->slaveData_.size())
{
slaveData.setSize(ptr->slaveData_.size());
forAll(slaveData, proci)
{
if (ptr->slaveData_.set(proci))
{
slaveData.set
(
proci,
new SubList<char>
(
ptr->slaveData_[proci],
ptr->sizes_[proci]
)
);
}
}
}
bool ok = writeFile
(
ptr->comm_,
@ -171,9 +218,7 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
ptr->pathName_,
ptr->data_,
ptr->sizes_,
ptr->haveSlaveData_,
ptr->slaveData_,
slaveData,
ptr->format_,
ptr->version_,
ptr->compression_,
@ -196,9 +241,10 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
Pout<< "OFstreamCollator : Exiting write thread " << endl;
}
lockMutex(handler.mutex_);
handler.threadRunning_ = false;
unlockMutex(handler.mutex_);
{
std::lock_guard<std::mutex> guard(handler.mutex_);
handler.threadRunning_ = false;
}
return nullptr;
}
@ -211,12 +257,13 @@ void Foam::OFstreamCollator::waitForBufferSpace(const off_t wantedSize) const
// Count files to be written
off_t totalSize = 0;
lockMutex(mutex_);
forAllConstIter(FIFOStack<writeData*>, objects_, iter)
{
totalSize += iter()->size();
std::lock_guard<std::mutex> guard(mutex_);
forAllConstIter(FIFOStack<writeData*>, objects_, iter)
{
totalSize += iter()->size();
}
}
unlockMutex(mutex_);
if (totalSize == 0 || (totalSize+wantedSize) <= maxBufferSize_)
{
@ -225,13 +272,12 @@ void Foam::OFstreamCollator::waitForBufferSpace(const off_t wantedSize) const
if (debug)
{
lockMutex(mutex_);
std::lock_guard<std::mutex> guard(mutex_);
Pout<< "OFstreamCollator : Waiting for buffer space."
<< " Currently in use:" << totalSize
<< " limit:" << maxBufferSize_
<< " files:" << objects_.size()
<< endl;
unlockMutex(mutex_);
}
sleep(5);
@ -244,25 +290,34 @@ void Foam::OFstreamCollator::waitForBufferSpace(const off_t wantedSize) const
Foam::OFstreamCollator::OFstreamCollator(const off_t maxBufferSize)
:
maxBufferSize_(maxBufferSize),
mutex_
(
maxBufferSize_ > 0
? allocateMutex()
: -1
),
thread_
(
maxBufferSize_ > 0
? allocateThread()
: -1
),
threadRunning_(false),
comm_
localComm_(UPstream::worldComm),
threadComm_
(
UPstream::allocateCommunicator
(
UPstream::worldComm,
identity(UPstream::nProcs(UPstream::worldComm))
localComm_,
identity(UPstream::nProcs(localComm_))
)
)
{}
Foam::OFstreamCollator::OFstreamCollator
(
const off_t maxBufferSize,
const label comm
)
:
maxBufferSize_(maxBufferSize),
threadRunning_(false),
localComm_(comm),
threadComm_
(
UPstream::allocateCommunicator
(
localComm_,
identity(UPstream::nProcs(localComm_))
)
)
{}
@ -272,26 +327,19 @@ Foam::OFstreamCollator::OFstreamCollator(const off_t maxBufferSize)
Foam::OFstreamCollator::~OFstreamCollator()
{
if (threadRunning_)
if (thread_.valid())
{
if (debug)
{
Pout<< "~OFstreamCollator : Waiting for write thread" << endl;
}
thread_().join();
thread_.clear();
}
joinThread(thread_);
}
if (thread_ != -1)
if (threadComm_ != -1)
{
freeThread(thread_);
}
if (mutex_ != -1)
{
freeMutex(mutex_);
}
if (comm_ != -1)
{
UPstream::freeCommunicator(comm_);
UPstream::freeCommunicator(threadComm_);
}
}
@ -312,7 +360,8 @@ bool Foam::OFstreamCollator::write
// Determine (on master) sizes to receive. Note: do NOT use thread
// communicator
labelList recvSizes;
decomposedBlockData::gather(Pstream::worldComm, data.size(), recvSizes);
decomposedBlockData::gather(localComm_, label(data.size()), recvSizes);
off_t totalSize = 0;
label maxLocalSize = 0;
{
@ -321,8 +370,8 @@ bool Foam::OFstreamCollator::write
totalSize += recvSizes[proci];
maxLocalSize = max(maxLocalSize, recvSizes[proci]);
}
Pstream::scatter(totalSize, Pstream::msgType(), Pstream::worldComm);
Pstream::scatter(maxLocalSize, Pstream::msgType(), Pstream::worldComm);
Pstream::scatter(totalSize, Pstream::msgType(), localComm_);
Pstream::scatter(maxLocalSize, Pstream::msgType(), localComm_);
}
if (maxBufferSize_ == 0 || maxLocalSize > maxBufferSize_)
@ -330,18 +379,17 @@ bool Foam::OFstreamCollator::write
if (debug)
{
Pout<< "OFstreamCollator : non-thread gather and write of " << fName
<< " using worldComm" << endl;
<< " using local comm " << localComm_ << endl;
}
// Direct collating and writing (so master blocks until all written!)
const List<char> dummySlaveData;
const PtrList<SubList<char>> dummySlaveData;
return writeFile
(
UPstream::worldComm,
localComm_,
typeName,
fName,
data,
recvSizes,
false, // no slave data provided yet
dummySlaveData,
fmt,
ver,
@ -360,22 +408,28 @@ bool Foam::OFstreamCollator::write
<< fName << endl;
}
if (Pstream::master())
if (Pstream::master(localComm_))
{
waitForBufferSpace(totalSize);
}
// Allocate local buffer for all collated data
// Receive in chunks of labelMax (2^31-1) since this is the maximum
// size that a List can be
autoPtr<writeData> fileAndDataPtr
(
new writeData
(
comm_, // Note: comm not actually used anymore
threadComm_, // Note: comm not actually used anymore
typeName,
fName,
data,
(
Pstream::master(localComm_)
? data // Only used on master
: string::null
),
recvSizes,
true, // have slave data (collected below)
fmt,
ver,
cmp,
@ -384,40 +438,84 @@ bool Foam::OFstreamCollator::write
);
writeData& fileAndData = fileAndDataPtr();
// Gather the slave data and insert into fileAndData
PtrList<List<char>>& slaveData = fileAndData.slaveData_;
UList<char> slice(const_cast<char*>(data.data()), label(data.size()));
List<int> slaveOffsets;
decomposedBlockData::gatherSlaveData
(
Pstream::worldComm, // Note: using simulation thread
slice,
recvSizes,
1, // startProc,
Pstream::nProcs()-1, // n procs
slaveData.setSize(recvSizes.size());
slaveOffsets,
fileAndData.slaveData_
);
// Append to thread buffer
lockMutex(mutex_);
objects_.push(fileAndDataPtr.ptr());
unlockMutex(mutex_);
// Start thread if not running
lockMutex(mutex_);
if (!threadRunning_)
// Gather all data onto master. Is done in local communicator since
// not in write thread. Note that we do not store in contiguous
// buffer since that would limit to 2G chars.
label startOfRequests = Pstream::nRequests();
if (Pstream::master(localComm_))
{
createThread(thread_, writeAll, this);
if (debug)
for (label proci = 1; proci < slaveData.size(); proci++)
{
Pout<< "OFstreamCollator : Started write thread "
<< thread_ << endl;
slaveData.set(proci, new List<char>(recvSizes[proci]));
UIPstream::read
(
UPstream::commsTypes::nonBlocking,
proci,
reinterpret_cast<char*>(slaveData[proci].begin()),
slaveData[proci].byteSize(),
Pstream::msgType(),
localComm_
);
}
}
else
{
if
(
!UOPstream::write
(
UPstream::commsTypes::nonBlocking,
0,
reinterpret_cast<const char*>(slice.begin()),
slice.byteSize(),
Pstream::msgType(),
localComm_
)
)
{
FatalErrorInFunction
<< "Cannot send outgoing message. "
<< "to:" << 0 << " nBytes:"
<< label(slice.byteSize())
<< Foam::abort(FatalError);
}
}
Pstream::waitRequests(startOfRequests);
{
std::lock_guard<std::mutex> guard(mutex_);
// Append to thread buffer
objects_.push(fileAndDataPtr.ptr());
// Start thread if not running
if (!threadRunning_)
{
if (thread_.valid())
{
if (debug)
{
Pout<< "OFstreamCollator : Waiting for write thread"
<< endl;
}
thread_().join();
}
if (debug)
{
Pout<< "OFstreamCollator : Starting write thread"
<< endl;
}
thread_.reset(new std::thread(writeAll, this));
threadRunning_ = true;
}
threadRunning_ = true;
}
unlockMutex(mutex_);
return true;
}
@ -426,57 +524,65 @@ bool Foam::OFstreamCollator::write
if (debug)
{
Pout<< "OFstreamCollator : thread gather and write of " << fName
<< " in thread " << thread_
<< " using communicator " << comm_ << endl;
<< " using communicator " << threadComm_ << endl;
}
if (!UPstream::haveThreads())
{
FatalErrorInFunction
<< "mpi does not seem to have thread support."
<< "Please increase the buffer size 'maxThreadFileBufferSize'"
<< " Make sure to set buffer size 'maxThreadFileBufferSize'"
<< " to at least " << totalSize
<< " to be able to do the collating before threading."
<< exit(FatalError);
}
if (Pstream::master())
if (Pstream::master(localComm_))
{
waitForBufferSpace(data.size());
}
lockMutex(mutex_);
// Push all file info on buffer. Note that no slave data provided
// so it will trigger communication inside the thread
objects_.push
(
new writeData
(
comm_,
typeName,
fName,
data,
recvSizes,
false, // Have no slave data; collect in thread
fmt,
ver,
cmp,
append
)
);
unlockMutex(mutex_);
lockMutex(mutex_);
if (!threadRunning_)
{
createThread(thread_, writeAll, this);
if (debug)
std::lock_guard<std::mutex> guard(mutex_);
// Push all file info on buffer. Note that no slave data provided
// so it will trigger communication inside the thread
objects_.push
(
new writeData
(
threadComm_,
typeName,
fName,
data,
recvSizes,
fmt,
ver,
cmp,
append
)
);
if (!threadRunning_)
{
Pout<< "OFstreamCollator : Started write thread " << endl;
if (thread_.valid())
{
if (debug)
{
Pout<< "OFstreamCollator : Waiting for write thread"
<< endl;
}
thread_().join();
}
if (debug)
{
Pout<< "OFstreamCollator : Starting write thread" << endl;
}
thread_.reset(new std::thread(writeAll, this));
threadRunning_ = true;
}
threadRunning_ = true;
}
unlockMutex(mutex_);
return true;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -51,9 +51,12 @@ SourceFiles
#ifndef OFstreamCollator_H
#define OFstreamCollator_H
#include <thread>
#include <mutex>
#include "IOstream.H"
#include "labelList.H"
#include "FIFOStack.H"
#include "SubList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -77,10 +80,7 @@ class OFstreamCollator
const fileName pathName_;
const string data_;
const labelList sizes_;
const bool haveSlaveData_;
List<char> slaveData_;
PtrList<List<char>> slaveData_;
const IOstream::streamFormat format_;
const IOstream::versionNumber version_;
const IOstream::compressionType compression_;
@ -93,7 +93,6 @@ class OFstreamCollator
const fileName& pathName,
const string& data,
const labelList& sizes,
const bool haveSlaveData,
IOstream::streamFormat format,
IOstream::versionNumber version,
IOstream::compressionType compression,
@ -105,7 +104,6 @@ class OFstreamCollator
pathName_(pathName),
data_(data),
sizes_(sizes),
haveSlaveData_(haveSlaveData),
slaveData_(0),
format_(format),
version_(version),
@ -116,27 +114,39 @@ class OFstreamCollator
//- (approximate) size of master + any optional slave data
off_t size() const
{
return data_.size() + slaveData_.size();
off_t sz = data_.size();
forAll(slaveData_, i)
{
if (slaveData_.set(i))
{
sz += slaveData_[i].size();
}
}
return sz;
}
};
// Private data
//- Total amount of storage to use for object stack below
const off_t maxBufferSize_;
//pthread_mutex_t mutex_;
label mutex_;
mutable std::mutex mutex_;
//pthread_t thread_;
label thread_;
autoPtr<std::thread> thread_;
//- Stack of files to write + contents
FIFOStack<writeData*> objects_;
//- Whether thread is running (and not exited)
bool threadRunning_;
//- Communicator to use for all parallel ops
label comm_;
//- Communicator to use for all parallel ops (in simulation thread)
label localComm_;
//- Communicator to use for all parallel ops (in write thread)
label threadComm_;
// Private Member Functions
@ -149,8 +159,7 @@ class OFstreamCollator
const fileName& fName,
const string& masterData,
const labelUList& recvSizes,
const bool haveSlaveData, // (does master) have slave data
const UList<char>& slaveData, // (on master) all slave data
const PtrList<SubList<char>>& slaveData,
IOstream::streamFormat fmt,
IOstream::versionNumber ver,
IOstream::compressionType cmp,
@ -176,6 +185,10 @@ public:
//- Construct from buffer size. 0 = do not use thread
OFstreamCollator(const off_t maxBufferSize);
//- Construct from buffer size (0 = do not use thread) and local
// thread
OFstreamCollator(const off_t maxBufferSize, const label comm);
//- Destructor
virtual ~OFstreamCollator();

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -57,12 +57,63 @@ namespace fileOperations
float,
collatedFileOperation::maxThreadFileBufferSize
);
// Mark as needing threaded mpi
addNamedToRunTimeSelectionTable
(
fileOperationInitialise,
collatedFileOperationInitialise,
word,
collated
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::labelList Foam::fileOperations::collatedFileOperation::ioRanks()
{
labelList ioRanks;
string ioRanksString(getEnv("FOAM_IORANKS"));
if (!ioRanksString.empty())
{
IStringStream is(ioRanksString);
is >> ioRanks;
}
return ioRanks;
}
bool Foam::fileOperations::collatedFileOperation::isMasterRank
(
const label proci
)
const
{
if (Pstream::parRun())
{
return Pstream::master(comm_);
}
else
{
// Use any IO ranks
if (ioRanks_.size())
{
// Find myself in IO rank
return findIndex(ioRanks_, proci) != -1;
}
else
{
// Assume all in single communicator
return proci == 0;
}
}
}
bool Foam::fileOperations::collatedFileOperation::appendObject
(
const regIOobject& io,
@ -74,14 +125,12 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
{
// Append to processors/ file
fileName prefix;
fileName postfix;
label proci = splitProcessorPath(io.objectPath(), prefix, postfix);
label proci = detectProcessorPath(io.objectPath());
if (debug)
{
Pout<< "writeObject:" << " : For local object : "
<< io.name()
Pout<< "collatedFileOperation::writeObject :"
<< " For local object : " << io.name()
<< " appending processor " << proci
<< " data to " << pathName << endl;
}
@ -93,12 +142,35 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
<< exit(FatalError);
}
const bool isMaster = isMasterRank(proci);
// Determine the local rank if the pathName is a per-rank one
label localProci = proci;
{
fileName path, procDir, local;
label groupStart, groupSize, nProcs;
splitProcessorPath
(
pathName,
path,
procDir,
local,
groupStart,
groupSize,
nProcs
);
if (groupSize > 0 && groupStart != -1)
{
localProci = proci-groupStart;
}
}
// Create string from all data to write
string buf;
{
OStringStream os(fmt, ver);
if (proci == 0)
if (isMaster)
{
if (!io.writeHeader(os))
{
@ -112,7 +184,7 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
return false;
}
if (proci == 0)
if (isMaster)
{
IOobject::writeEndDivider(os);
}
@ -121,8 +193,6 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
}
bool append = (proci > 0);
// Note: cannot do append + compression. This is a limitation
// of ogzstream (or rather most compressed formats)
@ -132,7 +202,7 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
IOstream::BINARY,
ver,
IOstream::UNCOMPRESSED, // no compression
append
!isMaster
);
if (!os.good())
@ -142,7 +212,7 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
<< exit(FatalIOError);
}
if (proci == 0)
if (isMaster)
{
IOobject::writeBanner(os)
<< "FoamFile\n{\n"
@ -162,7 +232,7 @@ bool Foam::fileOperations::collatedFileOperation::appendObject
const_cast<char*>(buf.data()),
label(buf.size())
);
os << nl << "// Processor" << proci << nl << slice << nl;
os << nl << "// Processor" << localProci << nl << slice << nl;
return os.good();
}
@ -175,8 +245,23 @@ Foam::fileOperations::collatedFileOperation::collatedFileOperation
const bool verbose
)
:
masterUncollatedFileOperation(false),
writer_(maxThreadFileBufferSize)
masterUncollatedFileOperation
(
(
ioRanks().size()
? UPstream::allocateCommunicator
(
UPstream::worldComm,
subRanks(Pstream::nProcs())
)
: UPstream::worldComm
),
false
),
myComm_(comm_),
writer_(maxThreadFileBufferSize, comm_),
nProcs_(Pstream::nProcs()),
ioRanks_(ioRanks())
{
if (verbose)
{
@ -195,12 +280,97 @@ Foam::fileOperations::collatedFileOperation::collatedFileOperation
{
Info<< " Threading activated "
"since maxThreadFileBufferSize > 0." << nl
<< " Requires thread support enabled in MPI, "
"otherwise the simulation" << nl
<< " may \"hang\". If thread support cannot be "
"enabled, deactivate threading" << nl
<< " by setting maxThreadFileBufferSize to 0 in "
"the OpenFOAM etc/controlDict"
<< " Requires large enough buffer to collect all data"
" or thread support " << nl
<< " enabled in MPI. If thread support cannot be "
"enabled, deactivate" << nl
<< " threading by setting maxThreadFileBufferSize "
"to 0 in" << nl
<< " $FOAM_ETC/controlDict"
<< endl;
}
if (ioRanks_.size())
{
// Print a bit of information
stringList ioRanks(Pstream::nProcs());
if (Pstream::master(comm_))
{
ioRanks[Pstream::myProcNo()] = hostName()+"."+name(pid());
}
Pstream::gatherList(ioRanks);
Info<< " IO nodes:" << endl;
forAll(ioRanks, proci)
{
if (!ioRanks[proci].empty())
{
Info<< " " << ioRanks[proci] << endl;
}
}
}
if
(
regIOobject::fileModificationChecking
== regIOobject::inotifyMaster
)
{
WarningInFunction
<< "Resetting fileModificationChecking to inotify" << endl;
}
if
(
regIOobject::fileModificationChecking
== regIOobject::timeStampMaster
)
{
WarningInFunction
<< "Resetting fileModificationChecking to timeStamp" << endl;
}
}
}
Foam::fileOperations::collatedFileOperation::collatedFileOperation
(
const label comm,
const labelList& ioRanks,
const word& typeName,
const bool verbose
)
:
masterUncollatedFileOperation(comm, false),
myComm_(-1),
writer_(maxThreadFileBufferSize, comm),
nProcs_(Pstream::nProcs()),
ioRanks_(ioRanks)
{
if (verbose)
{
Info<< "I/O : " << typeName
<< " (maxThreadFileBufferSize " << maxThreadFileBufferSize
<< ')' << endl;
if (maxThreadFileBufferSize == 0)
{
Info<< " Threading not activated "
"since maxThreadFileBufferSize = 0." << nl
<< " Writing may run slowly for large file sizes."
<< endl;
}
else
{
Info<< " Threading activated "
"since maxThreadFileBufferSize > 0." << nl
<< " Requires large enough buffer to collect all data"
" or thread support " << nl
<< " enabled in MPI. If thread support cannot be "
"enabled, deactivate" << nl
<< " threading by setting maxThreadFileBufferSize "
"to 0 in the OpenFOAM etc/controlDict" << nl
<< endl;
}
@ -227,6 +397,17 @@ Foam::fileOperations::collatedFileOperation::collatedFileOperation
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileOperations::collatedFileOperation::~collatedFileOperation()
{
if (myComm_ != -1 && myComm_ != UPstream::worldComm)
{
UPstream::freeCommunicator(myComm_);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::fileName Foam::fileOperations::collatedFileOperation::objectPath
@ -238,19 +419,21 @@ Foam::fileName Foam::fileOperations::collatedFileOperation::objectPath
// Replacement for objectPath
if (io.time().processorCase())
{
return masterUncollatedFileOperation::objectPath
return masterUncollatedFileOperation::localObjectPath
(
io,
fileOperation::PROCESSORSOBJECT,
fileOperation::PROCOBJECT,
"dummy", // not used for processorsobject
io.instance()
);
}
else
{
return masterUncollatedFileOperation::objectPath
return masterUncollatedFileOperation::localObjectPath
(
io,
fileOperation::OBJECT,
word::null,
io.instance()
);
}
@ -276,8 +459,8 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
if (debug)
{
Pout<< "writeObject:"
<< " : For object : " << io.name()
Pout<< "collatedFileOperation::writeObject :"
<< " For object : " << io.name()
<< " falling back to master-only output to " << io.path()
<< endl;
}
@ -313,7 +496,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
else
{
// Construct the equivalent processors/ directory
fileName path(processorsPath(io, inst));
fileName path(processorsPath(io, inst, processorsDir(io)));
mkDir(path);
fileName pathName(path/io.name());
@ -322,7 +505,8 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
{
if (debug)
{
Pout<< "writeObject:" << " : For global object : " << io.name()
Pout<< "collatedFileOperation::writeObject :"
<< " For global object : " << io.name()
<< " falling back to master-only output to " << pathName
<< endl;
}
@ -359,11 +543,11 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
else if (!Pstream::parRun())
{
// Special path for e.g. decomposePar. Append to
// processors/ file
// processorsDDD/ file
if (debug)
{
Pout<< "writeObject:"
<< " : For object : " << io.name()
Pout<< "collatedFileOperation::writeObject :"
<< " For object : " << io.name()
<< " appending to " << pathName << endl;
}
@ -373,8 +557,8 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
{
if (debug)
{
Pout<< "writeObject:"
<< " : For object : " << io.name()
Pout<< "collatedFileOperation::writeObject :"
<< " For object : " << io.name()
<< " starting collating output to " << pathName << endl;
}
@ -386,7 +570,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
{
return false;
}
if (Pstream::master() && !io.writeHeader(os))
if (Pstream::master(comm_) && !io.writeHeader(os))
{
return false;
}
@ -395,7 +579,7 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
{
return false;
}
if (Pstream::master())
if (Pstream::master(comm_))
{
IOobject::writeEndDivider(os);
}
@ -406,4 +590,89 @@ bool Foam::fileOperations::collatedFileOperation::writeObject
}
Foam::word Foam::fileOperations::collatedFileOperation::processorsDir
(
const fileName& fName
) const
{
if (Pstream::parRun())
{
const List<int>& procs(UPstream::procID(comm_));
word procDir(processorsBaseDir+Foam::name(Pstream::nProcs()));
if (procs.size() != Pstream::nProcs())
{
procDir +=
+ "_"
+ Foam::name(procs[0])
+ "-"
+ Foam::name(procs.last());
}
return procDir;
}
else
{
word procDir(processorsBaseDir+Foam::name(nProcs_));
if (ioRanks_.size())
{
// Detect current processor number
label proci = detectProcessorPath(fName);
if (proci != -1)
{
// Find lowest io rank
label minProc = 0;
label maxProc = nProcs_-1;
forAll(ioRanks_, i)
{
if (ioRanks_[i] >= nProcs_)
{
break;
}
else if (ioRanks_[i] <= proci)
{
minProc = ioRanks_[i];
}
else
{
maxProc = ioRanks_[i]-1;
break;
}
}
procDir +=
+ "_"
+ Foam::name(minProc)
+ "-"
+ Foam::name(maxProc);
}
}
return procDir;
}
}
Foam::word Foam::fileOperations::collatedFileOperation::processorsDir
(
const IOobject& io
) const
{
return processorsDir(io.objectPath());
}
void Foam::fileOperations::collatedFileOperation::setNProcs(const label nProcs)
{
nProcs_ = nProcs;
if (debug)
{
Pout<< "collatedFileOperation::setNProcs :"
<< " Setting number of processors to " << nProcs_ << endl;
}
}
// ************************************************************************* //

View File

@ -43,6 +43,7 @@ SourceFiles
#include "masterUncollatedFileOperation.H"
#include "OFstreamCollator.H"
#include "fileOperationInitialise.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -59,14 +60,33 @@ class collatedFileOperation
:
public masterUncollatedFileOperation
{
// Private data
protected:
// Protected data
//- Any communicator allocated by me
const label myComm_;
//- Threaded writer
mutable OFstreamCollator writer_;
// For non-parallel operation
//- Number of processors (overall)
label nProcs_;
//- Ranks of IO handlers
const labelList ioRanks_;
// Private Member Functions
static labelList ioRanks();
//- Is proci master of communicator (in parallel) or master of
// the io ranks (non-parallel)
bool isMasterRank(const label proci) const;
//- Append to processors/ file
bool appendObject
(
@ -97,9 +117,18 @@ public:
//- Construct null
collatedFileOperation(const bool verbose);
//- Construct from user communicator
collatedFileOperation
(
const label comm,
const labelList& ioRanks,
const word& typeName,
const bool verbose
);
//- Destructor
virtual ~collatedFileOperation() = default;
virtual ~collatedFileOperation();
// Member Functions
@ -123,6 +152,54 @@ public:
IOstream::compressionType compression=IOstream::UNCOMPRESSED,
const bool valid = true
) const;
// Other
//- Actual name of processors dir
virtual word processorsDir(const IOobject&) const;
//- Actual name of processors dir
virtual word processorsDir(const fileName&) const;
//- Set number of processor directories/results. Only used in
// decomposePar
virtual void setNProcs(const label nProcs);
};
/*---------------------------------------------------------------------------*\
Class collatedFileOperationInitialise Declaration
\*---------------------------------------------------------------------------*/
class collatedFileOperationInitialise
:
public masterUncollatedFileOperationInitialise
{
public:
// Constructors
//- Construct from components
collatedFileOperationInitialise(int& argc, char**& argv)
:
masterUncollatedFileOperationInitialise(argc, argv)
{}
//- Destructor
virtual ~collatedFileOperationInitialise()
{}
// Member Functions
//- Needs threading
virtual bool needsThreading() const
{
return
collatedFileOperation::maxThreadFileBufferSize
> 0;
}
};

View File

@ -0,0 +1,176 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "hostCollatedFileOperation.H"
#include "addToRunTimeSelectionTable.H"
#include "bitSet.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
namespace Foam
{
namespace fileOperations
{
defineTypeNameAndDebug(hostCollatedFileOperation, 0);
addToRunTimeSelectionTable
(
fileOperation,
hostCollatedFileOperation,
word
);
// Register initialisation routine. Signals need for threaded mpi and
// handles command line arguments
addNamedToRunTimeSelectionTable
(
fileOperationInitialise,
hostCollatedFileOperationInitialise,
word,
hostCollated
);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::labelList Foam::fileOperations::hostCollatedFileOperation::subRanks
(
const label n
)
{
DynamicList<label> subRanks(64);
string ioRanksString(getEnv("FOAM_IORANKS"));
if (!ioRanksString.empty())
{
IStringStream is(ioRanksString);
labelList ioRanks(is);
if (findIndex(ioRanks, 0) == -1)
{
FatalErrorInFunction
<< "Rank 0 (master) should be in the IO ranks. Currently "
<< ioRanks << exit(FatalError);
}
// The lowest numbered rank is the IO rank
const bitSet isIOrank(n, ioRanks);
for (label proci = Pstream::myProcNo(); proci >= 0; --proci)
{
if (isIOrank[proci])
{
// Found my master. Collect all processors with same master
subRanks.append(proci);
for
(
label rank = proci+1;
rank < n && !isIOrank[rank];
++rank
)
{
subRanks.append(rank);
}
break;
}
}
}
else
{
// Normal operation: one lowest rank per hostname is the writer
const string myHostName(hostName());
stringList hosts(Pstream::nProcs());
hosts[Pstream::myProcNo()] = myHostName;
Pstream::gatherList(hosts);
Pstream::scatterList(hosts);
// Collect procs with same hostname
forAll(hosts, proci)
{
if (hosts[proci] == myHostName)
{
subRanks.append(proci);
}
}
}
return subRanks;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileOperations::hostCollatedFileOperation::hostCollatedFileOperation
(
const bool verbose
)
:
collatedFileOperation
(
UPstream::allocateCommunicator
(
UPstream::worldComm,
subRanks(Pstream::nProcs())
),
(Pstream::parRun() ? labelList(0) : ioRanks()), // processor dirs
typeName,
verbose
)
{
if (verbose)
{
// Print a bit of information
stringList ioRanks(Pstream::nProcs());
if (Pstream::master(comm_))
{
ioRanks[Pstream::myProcNo()] = hostName()+"."+name(pid());
}
Pstream::gatherList(ioRanks);
Info<< " IO nodes:" << endl;
forAll(ioRanks, proci)
{
if (!ioRanks[proci].empty())
{
Info<< " " << ioRanks[proci] << endl;
}
}
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileOperations::hostCollatedFileOperation::~hostCollatedFileOperation()
{
if (comm_ != -1 && comm_ != UPstream::worldComm)
{
UPstream::freeCommunicator(comm_);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,134 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
Class
Foam::fileOperations::hostCollatedFileOperation
Description
Version of collatedFileOperation with multiple read/write ranks.
In parallel it will assume ranks are sorted according to hostname
and the lowest rank per hostname will be the IO rank. The output directories
will get a unique name processors<N>_<low>-<high> where N is the overall
number of processors and low and high is the range of ranks contained
in the files. Each of these subsets uses its own communicator.
Instead of using the hostnames the IO ranks can be assigned using the
FOAM_IORANKS environment variable (also when running non-parallel), e.g.
when decomposing into 4:
FOAM_IORANKS='(0 2)' decomposePar -fileHandler hostCollated
will generate
processors4_0-1/
containing data for processors 0 to 1
processors4_2-3/
containing data for processors 2 to 3
See also
collatedFileOperation
SourceFiles
hostCollatedFileOperation.C
\*---------------------------------------------------------------------------*/
#ifndef fileOperations_hostCollatedFileOperation_H
#define fileOperations_hostCollatedFileOperation_H
#include "collatedFileOperation.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fileOperations
{
/*---------------------------------------------------------------------------*\
Class hostCollatedFileOperation Declaration
\*---------------------------------------------------------------------------*/
class hostCollatedFileOperation
:
public collatedFileOperation
{
// Private Member Functions
//- Get the list of processors part of this set
static labelList subRanks(const label n);
public:
//- Runtime type information
TypeName("hostCollated");
// Constructors
//- Construct null
hostCollatedFileOperation(const bool verbose);
//- Destructor
virtual ~hostCollatedFileOperation();
};
/*---------------------------------------------------------------------------*\
Class hostCollatedFileOperationInitialise Declaration
\*---------------------------------------------------------------------------*/
class hostCollatedFileOperationInitialise
:
public collatedFileOperationInitialise
{
public:
// Constructors
//- Construct from components
hostCollatedFileOperationInitialise(int& argc, char**& argv)
:
collatedFileOperationInitialise(argc, argv)
{}
//- Destructor
virtual ~hostCollatedFileOperationInitialise()
{}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fileOperations
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -28,11 +28,11 @@ License
#include "regIOobject.H"
#include "argList.H"
#include "HashSet.H"
#include "masterUncollatedFileOperation.H"
#include "objectRegistry.H"
#include "decomposedBlockData.H"
#include "polyMesh.H"
#include "registerSwitch.H"
#include "Time.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
@ -43,6 +43,28 @@ namespace Foam
defineTypeNameAndDebug(fileOperation, 0);
defineRunTimeSelectionTable(fileOperation, word);
template<>
const char* Foam::NamedEnum
<
fileOperation::pathType,
12
>::names[] =
{
"notFound",
"absolute",
"objectPath",
"writeObject",
"uncollatedProc",
"globalProc",
"localProc",
"parentObjectPath",
"findInstance",
"uncollatedProcInstance",
"globalProcInstance",
"localProcInstance"
};
const NamedEnum<fileOperation::pathType, 12> fileOperation::pathTypeNames_;
word fileOperation::defaultFileHandler
(
debug::optimisationSwitches().lookupOrAddDefault
@ -56,7 +78,7 @@ namespace Foam
);
}
Foam::word Foam::fileOperation::processorsDir = "processors";
Foam::word Foam::fileOperation::processorsBaseDir = "processors";
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -133,6 +155,80 @@ Foam::instantList Foam::fileOperation::sortTimes
}
void Foam::fileOperation::mergeTimes
(
const instantList& extraTimes,
const word& constantName,
instantList& times
)
{
if (extraTimes.size())
{
bool haveConstant =
(
times.size() > 0
&& times[0].name() == constantName
);
bool haveExtraConstant =
(
extraTimes.size() > 0
&& extraTimes[0].name() == constantName
);
// Combine times
instantList combinedTimes(times.size()+extraTimes.size());
label sz = 0;
label extrai = 0;
if (haveExtraConstant)
{
extrai = 1;
if (!haveConstant)
{
combinedTimes[sz++] = extraTimes[0]; // constant
}
}
forAll(times, i)
{
combinedTimes[sz++] = times[i];
}
for (; extrai < extraTimes.size(); extrai++)
{
combinedTimes[sz++] = extraTimes[extrai];
}
combinedTimes.setSize(sz);
times.transfer(combinedTimes);
// Sort
if (times.size() > 1)
{
label starti = 0;
if (times[0].name() == constantName)
{
starti = 1;
}
std::sort(&times[starti], times.end(), instant::less());
// Filter out duplicates
label newi = starti+1;
for (label i = newi; i < times.size(); i++)
{
if (times[i].value() != times[i-1].value())
{
if (newi != i)
{
times[newi] = times[i];
}
newi++;
}
}
times.setSize(newi);
}
}
}
bool Foam::fileOperation::isFileOrDir(const bool isFile, const fileName& f)
{
return
@ -141,8 +237,182 @@ bool Foam::fileOperation::isFileOrDir(const bool isFile, const fileName& f)
}
Foam::tmpNrc<Foam::fileOperation::dirIndexList>
Foam::fileOperation::lookupProcessorsPath(const fileName& fName) const
{
// If path is local to a processor (e.g. contains 'processor2')
// find the corresponding actual processor directory (e.g. 'processors4')
// and index (2)
fileName path;
fileName pDir;
fileName local;
label gStart;
label gSz;
label numProcs;
label proci =
splitProcessorPath(fName, path, pDir, local, gStart, gSz, numProcs);
if (proci != -1)
{
const fileName procPath(path/pDir);
HashTable<dirIndexList>::const_iterator iter =
procsDirs_.find(procPath);
if (iter != procsDirs_.end())
{
return iter();
}
// Read all directories to see any beginning with processor
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DynamicList<dirIndex> procDirs;
// Note: use parallel synchronised reading so cache will be same
// order on all processors
fileNameList dirNames(readDir(path, fileName::Type::DIRECTORY));
// Extract info from processorsDDD or processorDDD:
// - highest processor number
// - directory+offset containing data for proci
label maxProc = -1;
forAll(dirNames, i)
{
const fileName& dirN = dirNames[i];
// Analyse directory name
fileName rp, rd, rl;
label rStart, rSize, rNum;
label readProci =
splitProcessorPath(dirN, rp, rd, rl, rStart, rSize, rNum);
maxProc = max(maxProc, readProci);
if (proci == readProci)
{
// Found "processorDDD". No need for index.
procDirs.append
(
dirIndex
(
dirN,
Tuple2<pathType, label>(PROCUNCOLLATED, -1)
)
);
}
else if (proci >= rStart && proci < rStart+rSize)
{
// "processorsDDD_start-end"
// Found the file that contains the data for proci
procDirs.append
(
dirIndex
(
dirN,
Tuple2<pathType, label>(PROCOBJECT, proci-rStart)
)
);
}
if (rNum != -1)
{
// Direct detection of processorsDDD
maxProc = rNum-1;
if (rStart == -1)
{
// "processorsDDD"
procDirs.append
(
dirIndex
(
dirN,
Tuple2<pathType, label>(PROCBASEOBJECT, proci)
)
);
}
}
}
if (!Pstream::parRun())
{
// If (as a side effect) we found the number of decompositions
// use it
if (maxProc != -1)
{
const_cast<fileOperation&>(*this).setNProcs(maxProc+1);
}
}
if (returnReduce(procDirs.size(), sumOp<label>()))
{
procsDirs_.insert(procPath, procDirs);
if (debug)
{
Pout<< "fileOperation::lookupProcessorsPath : For:" << procPath
<< " detected:" << procDirs << endl;
}
// Make sure to return a reference
return procsDirs_[procPath];
}
}
return tmpNrc<dirIndexList>(new dirIndexList(0, dirIndex()));
}
bool Foam::fileOperation::exists(IOobject& io) const
{
// Generate output filename for object
fileName objPath(objectPath(io, word::null));
// Test for either directory or a (valid) file & IOobject
bool ok;
if (io.name().empty())
{
ok = isDir(objPath);
}
else
{
ok =
isFile(objPath)
&& io.typeHeaderOk<IOList<label>>(false);// object with local scope
}
if (!ok)
{
// Re-test with searched for objectPath. This is for backwards
// compatibility
fileName originalPath(filePath(io.objectPath()));
if (originalPath != objPath)
{
// Test for either directory or a (valid) file & IOobject
if (io.name().empty())
{
ok = isDir(originalPath);
}
else
{
ok =
isFile(originalPath)
&& io.typeHeaderOk<IOList<label>>(false);
}
}
}
return ok;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileOperation::fileOperation(label comm)
:
comm_(comm)
{}
Foam::autoPtr<Foam::fileOperation> Foam::fileOperation::New
(
const word& handlerType,
@ -238,37 +508,64 @@ bool Foam::fileOperation::writeObject
}
//Foam::fileName Foam::fileOperation::objectPath(const fileName& fName) const
//{
// return fName;
//}
Foam::fileName Foam::fileOperation::filePath(const fileName& fName) const
{
fileName path;
fileName local;
label proci = fileOperations::masterUncollatedFileOperation::
splitProcessorPath
(
fName,
path,
local
);
if (debug)
{
Pout<< "fileOperation::filePath :" << " fName:" << fName << endl;
}
fileName procsName(path/processorsDir/local);
fileName path;
fileName pDir;
fileName local;
label gStart;
label gSz;
label numProcs;
label proci =
splitProcessorPath(fName, path, pDir, local, gStart, gSz, numProcs);
if (numProcs != -1)
{
WarningInFunction << "Filename is already adapted:" << fName << endl;
}
// Give preference to processors variant
if (proci != -1 && exists(procsName))
if (proci != -1)
{
return procsName;
}
else if (exists(fName))
{
return fName;
// Get all processor directories
tmpNrc<dirIndexList> procDirs(lookupProcessorsPath(fName));
forAll(procDirs(), i)
{
const fileName& procDir = procDirs()[i].first();
fileName collatedName(path/procDir/local);
if (exists(collatedName))
{
if (debug)
{
Pout<< "fileOperation::filePath : " << collatedName << endl;
}
return collatedName;
}
}
}
return fileName::null;
if (exists(fName))
{
if (debug)
{
Pout<< "fileOperation::filePath : " << fName << endl;
}
return fName;
}
else
{
if (debug)
{
Pout<< "fileOperation::filePath : Not found" << endl;
}
return fileName::null;
}
}
@ -377,8 +674,8 @@ Foam::instantList Foam::fileOperation::findTimes
{
if (debug)
{
Pout<< FUNCTION_NAME
<< " : Finding times in directory " << directory << endl;
Pout<< "fileOperation::findTimes : Finding times in directory "
<< directory << endl;
}
// Read directory entries into a list
@ -393,103 +690,188 @@ Foam::instantList Foam::fileOperation::findTimes
instantList times = sortTimes(dirEntries, constantName);
// Check if directory is processorXXX
fileName procsDir
(
fileOperations::masterUncollatedFileOperation::processorsPath
(
directory
)
);
if (!procsDir.empty() && procsDir != directory)
// Get all processor directories
tmpNrc<dirIndexList> procDirs(lookupProcessorsPath(directory));
forAll(procDirs(), i)
{
fileNameList extraEntries
(
Foam::readDir
(
procsDir,
fileName::DIRECTORY
)
);
instantList extraTimes = sortTimes(extraEntries, constantName);
if (extraTimes.size())
const fileName& procDir = procDirs()[i].first();
fileName collDir(processorsPath(directory, procDir));
if (!collDir.empty() && collDir != directory)
{
bool haveConstant =
fileNameList extraEntries
(
times.size() > 0
&& times[0].name() == constantName
Foam::readDir
(
collDir,
fileName::DIRECTORY
)
);
bool haveExtraConstant =
mergeTimes
(
extraTimes.size() > 0
&& extraTimes[0].name() == constantName
sortTimes(extraEntries, constantName),
constantName,
times
);
// Combine times
instantList combinedTimes(times.size()+extraTimes.size());
label sz = 0;
label extrai = 0;
if (haveExtraConstant)
{
extrai = 1;
if (!haveConstant)
{
combinedTimes[sz++] = extraTimes[0]; // constant
}
}
forAll(times, i)
{
combinedTimes[sz++] = times[i];
}
for (; extrai < extraTimes.size(); extrai++)
{
combinedTimes[sz++] = extraTimes[extrai];
}
combinedTimes.setSize(sz);
times.transfer(combinedTimes);
// Sort
if (times.size() > 1)
{
label starti = 0;
if (times[0].name() == constantName)
{
starti = 1;
}
std::sort(&times[starti], times.end(), instant::less());
// Filter out duplicates
label newi = starti+1;
for (label i = newi; i < times.size(); i++)
{
if (times[i].value() != times[i-1].value())
{
if (newi != i)
{
times[newi] = times[i];
}
newi++;
}
}
times.setSize(newi);
}
}
}
if (debug)
{
Pout<< FUNCTION_NAME
<< " : Found times:" << times << endl;
Pout<< "fileOperation::findTimes : Found times:" << times << endl;
}
return times;
}
Foam::IOobject Foam::fileOperation::findInstance
(
const IOobject& startIO,
const scalar startValue,
const word& stopInstance
) const
{
const Time& time = startIO.time();
IOobject io(startIO);
// Note: - if name is empty, just check the directory itself
// - check both for isFile and headerOk since the latter does a
// filePath so searches for the file.
// - check for an object with local file scope (so no looking up in
// parent directory in case of parallel)
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found exact match for \"" << io.name()
<< "\" in " << io.instance()/io.local()
<< endl;
}
return io;
}
// Search back through the time directories to find the time
// closest to and lower than current time
instantList ts = time.times();
label instanceI;
for (instanceI = ts.size()-1; instanceI >= 0; --instanceI)
{
if (ts[instanceI].value() <= startValue)
{
break;
}
}
// continue searching from here
for (; instanceI >= 0; --instanceI)
{
// Shortcut: if actual directory is the timeName we've already tested it
if (ts[instanceI].name() == startIO.instance())
{
continue;
}
io.instance() = ts[instanceI].name();
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found exact match for \"" << io.name()
<< "\" in " << io.instance()/io.local()
<< endl;
}
return io;
}
// Check if hit minimum instance
if (ts[instanceI].name() == stopInstance)
{
if (debug)
{
InfoInFunction
<< "Hit stopInstance " << stopInstance << endl;
}
if
(
startIO.readOpt() == IOobject::MUST_READ
|| startIO.readOpt() == IOobject::MUST_READ_IF_MODIFIED
)
{
if (io.name().empty())
{
FatalErrorInFunction
<< "Cannot find directory "
<< io.local() << " in times " << startIO.instance()
<< " down to " << stopInstance
<< exit(FatalError);
}
else
{
FatalErrorInFunction
<< "Cannot find file \"" << io.name()
<< "\" in directory " << io.local()
<< " in times " << startIO.instance()
<< " down to " << stopInstance
<< exit(FatalError);
}
}
return io;
}
}
// times() usually already includes the constant() so would have been
// checked above. Re-test if
// - times() is empty. Sometimes this can happen (e.g. decomposePar with
// collated)
// - times()[0] is not constant
if (!ts.size() || ts[0].name() != time.constant())
{
// Note. This needs to be a hard-coded constant, rather than the
// constant function of the time, because the latter points to
// the case constant directory in parallel cases
io.instance() = time.constant();
if (exists(io))
{
if (debug)
{
InfoInFunction
<< "Found constant match for \"" << io.name()
<< "\" in " << io.instance()/io.local()
<< endl;
}
return io;
}
}
if
(
startIO.readOpt() == IOobject::MUST_READ
|| startIO.readOpt() == IOobject::MUST_READ_IF_MODIFIED
)
{
FatalErrorInFunction
<< "Cannot find file \"" << io.name() << "\" in directory "
<< io.local() << " in times " << startIO.instance()
<< " down to " << time.constant()
<< exit(FatalError);
}
return io;
}
Foam::fileNameList Foam::fileOperation::readObjects
(
const objectRegistry& db,
@ -518,19 +900,9 @@ Foam::fileNameList Foam::fileOperation::readObjects
else
{
// Get processors equivalent of path
fileName procsPath(filePath(path));
fileName prefix;
fileName postfix;
label proci = fileOperations::masterUncollatedFileOperation::
splitProcessorPath
(
path,
prefix,
postfix
);
fileName procsPath(prefix/processorsDir/postfix);
if (proci != -1 && Foam::isDir(procsPath))
if (!procsPath.empty())
{
newInstance = instance;
objectNames = Foam::readDir(procsPath, fileName::FILE);
@ -540,46 +912,252 @@ Foam::fileNameList Foam::fileOperation::readObjects
}
void Foam::fileOperation::setNProcs(const label nProcs)
{}
Foam::label Foam::fileOperation::nProcs
(
const fileName& dir,
const fileName& local
) const
{
if (Foam::isDir(dir/processorsDir))
label nProcs = 0;
if (Pstream::master(comm_))
{
fileName pointsFile
(
dir
/processorsDir
/"constant"
/local
/polyMesh::meshSubDir
/"points"
);
fileNameList dirNames(Foam::readDir(dir, fileName::Type::DIRECTORY));
if (Foam::isFile(pointsFile))
// Detect any processorsDDD or processorDDD
label maxProc = -1;
forAll(dirNames, i)
{
return decomposedBlockData::numBlocks(pointsFile);
const fileName& dirN = dirNames[i];
fileName path, pDir, local;
label start, size, n;
maxProc = max
(
maxProc,
splitProcessorPath(dirN, path, pDir, local, start, size, n)
);
if (n != -1)
{
// Direct detection of processorsDDD
maxProc = n-1;
break;
}
}
nProcs = maxProc+1;
if (nProcs == 0 && Foam::isDir(dir/processorsBaseDir))
{
fileName pointsFile
(
dir
/processorsBaseDir
/"constant"
/local
/polyMesh::meshSubDir
/"points"
);
if (Foam::isFile(pointsFile))
{
nProcs = decomposedBlockData::numBlocks(pointsFile);
}
else
{
WarningInFunction << "Cannot read file " << pointsFile
<< " to determine the number of decompositions."
<< " Returning 1" << endl;
}
}
}
Pstream::scatter(nProcs, Pstream::msgType(), comm_);
return nProcs;
}
Foam::fileName Foam::fileOperation::processorsCasePath
(
const IOobject& io,
const word& procsDir
) const
{
return io.rootPath()/io.time().globalCaseName()/procsDir;
}
Foam::fileName Foam::fileOperation::processorsPath
(
const IOobject& io,
const word& instance,
const word& procsDir
) const
{
return
processorsCasePath(io, procsDir)
/instance
/io.db().dbDir()
/io.local();
}
Foam::fileName Foam::fileOperation::processorsPath
(
const fileName& dir,
const word& procsDir
) const
{
// Check if directory is processorDDD
word caseName(dir.name());
std::string::size_type pos = caseName.find("processor");
if (pos == 0)
{
if (caseName.size() <= 9 || caseName[9] == 's')
{
WarningInFunction << "Directory " << dir
<< " does not end in old-style processorDDD" << endl;
}
return dir.path()/procsDir;
}
else
{
return fileName::null;
}
}
Foam::label Foam::fileOperation::splitProcessorPath
(
const fileName& objectPath,
fileName& path,
fileName& procDir,
fileName& local,
label& groupStart,
label& groupSize,
label& nProcs
)
{
path.clear();
procDir.clear();
local.clear();
// Potentially detected start of number of processors in local group
groupStart = -1;
groupSize = 0;
// Potentially detected number of processors
nProcs = -1;
// Search for processor at start of line or /processor
std::string::size_type pos = objectPath.find("processor");
if (pos == string::npos)
{
return -1;
}
// "processorDDD"
// "processorsNNN"
// "processorsNNN_AA-BB"
if (pos > 0 && objectPath[pos-1] != '/')
{
// Directory not starting with "processor" e.g. "somenamewithprocessor"
return -1;
}
procDir = objectPath;
// Strip leading directory
if (pos > 0)
{
path = objectPath.substr(0, pos-1);
procDir = objectPath.substr(pos);
}
// Strip trailing local directory
pos = procDir.find('/');
if (pos != string::npos)
{
local = procDir.substr(pos+1);
procDir = procDir.substr(0, pos);
}
// Now procDir is e.g.
// - processor0
// - processors0
// - processorBananas
// Look for number after "processor"
fileName f(procDir.substr(9));
if (f.size() && f[0] == 's')
{
// "processsorsNNN"
f = f.substr(1);
// Detect "processorsNNN_AA-BB"
{
std::string::size_type fromStart = f.find("_");
std::string::size_type toStart = f.find("-");
if (fromStart != string::npos && toStart != string::npos)
{
string nProcsName(f.substr(0, fromStart));
string fromName(f.substr(fromStart+1, toStart-(fromStart+1)));
string toName(f.substr(toStart+1));
label groupEnd = -1;
if
(
Foam::read(fromName.c_str(), groupStart)
&& Foam::read(toName.c_str(), groupEnd)
&& Foam::read(nProcsName.c_str(), nProcs)
)
{
groupSize = groupEnd-groupStart+1;
return -1;
}
}
}
// Detect "processorsN"
label n;
if (Foam::read(f.c_str(), n))
{
nProcs = n;
}
return -1;
}
else
{
// Detect "processorN"
label proci;
if (Foam::read(f.c_str(), proci))
{
return proci;
}
else
{
WarningInFunction << "Cannot read file " << pointsFile
<< " to determine the number of decompositions."
<< " Falling back to looking for processor.*" << endl;
return -1;
}
}
}
label nProcs = 0;
while
(
isDir(dir/(word("processor") + name(nProcs)))
)
{
++nProcs;
}
return nProcs;
Foam::label Foam::fileOperation::detectProcessorPath(const fileName& fName)
{
fileName path, pDir, local;
label start, size, nProcs;
return splitProcessorPath(fName, path, pDir, local, start, size, nProcs);
}

View File

@ -45,6 +45,10 @@ Description
#include "instantList.H"
#include "fileMonitor.H"
#include "labelList.H"
#include "Switch.H"
#include "tmpNrc.H"
#include "NamedEnum.H"
#include "Tuple2.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -56,16 +60,55 @@ class regIOobject;
class objectRegistry;
class Time;
// Description of processor directory naming:
// - processor directory naming
// - whether directory contains a range (so differs on different processors)
// - index in range
//typedef Tuple2<fileName, Tuple2<bool, label>> dirIndex;
//typedef List<dirIndex> dirIndexList;
/*---------------------------------------------------------------------------*\
Class fileOperation Declaration
\*---------------------------------------------------------------------------*/
class fileOperation
{
public:
//- Enumeration for the location of an IOobject
enum pathType
{
NOTFOUND, // not found
ABSOLUTE, // instance is absolute directory
OBJECT, // io.objectPath() exists
WRITEOBJECT, // write path exists
PROCUNCOLLATED, // objectPath exists in processor0
PROCBASEOBJECT, // objectPath exists in specified, constant
// processorsDir (usually 'processorsDDD')
PROCOBJECT, // objectPath exists in locally differing
// processorsDir (e.g. 'processorsDDD_0-1')
PARENTOBJECT, // parent of object path
FINDINSTANCE, // file found in time directory
PROCUNCOLLATEDINSTANCE, // as PROCUNCOLLATED but with instance
PROCBASEINSTANCE, // as PROCBASEOBJECT but with instance
PROCINSTANCE // as PROCOBJECT but with instance
};
static const NamedEnum<pathType, 12> pathTypeNames_;
typedef Tuple2<fileName, Tuple2<pathType, label>> dirIndex;
typedef List<dirIndex> dirIndexList;
protected:
// Protected data
//- Communicator to use
const label comm_;
//- Detected processors directories
mutable HashTable<dirIndexList> procsDirs_;
//- file-change monitor for all registered files
mutable autoPtr<fileMonitor> monitorPtr_;
@ -77,15 +120,35 @@ protected:
//- Sort directory entries according to time value
static instantList sortTimes(const fileNameList&, const word&);
//- Merge two times
static void mergeTimes
(
const instantList& extraTimes,
const word& constantName,
instantList& times
);
//- Helper: check for file (isFile) or directory (!isFile)
static bool isFileOrDir(const bool isFile, const fileName&);
//- Detect presence of processorsDDD
void cacheProcessorsPath(const fileName& fName) const;
//- Lookup name of processorsDDD using cache. Return empty fileName
// if not found
tmpNrc<dirIndexList> lookupProcessorsPath(const fileName&) const;
//- Does ioobject exist. Is either a directory (empty name()) or
// a file
bool exists(IOobject& io) const;
public:
// Static data
//- The processors directory name (usually "processors")
static word processorsDir;
//- Return the processors directory name (usually "processors")
static word processorsBaseDir;
//- Default fileHandler
static word defaultFileHandler;
@ -93,19 +156,6 @@ public:
// Public data types
//- Enumeration for the location of an IOobject
enum pathType
{
NOTFOUND, // not found
ABSOLUTE, // instance is absolute directory
OBJECT, // objectPath exists
PROCESSORSOBJECT, // objectPath exists in processors/
PARENTOBJECT, // parent of object path
FINDINSTANCE, // file found in time directory
PROCESSORSFINDINSTANCE // as above but in processors/
};
//- Runtime type information
TypeName("fileOperation");
@ -116,8 +166,8 @@ public:
// Constructors
//- Construct null
fileOperation() = default;
//- Construct from communicator
explicit fileOperation(const label comm);
// Declare run-time constructor selection table
@ -413,6 +463,24 @@ public:
// Other
//- Actual name of processors dir (for use in mode PROCOBJECT,
// PROCINSTANCE)
virtual word processorsDir(const IOobject& io) const
{
return processorsBaseDir;
}
//- Actual name of processors dir (for use in mode PROCOBJECT,
// PROCINSTANCE)
virtual word processorsDir(const fileName&) const
{
return processorsBaseDir;
}
//- Set number of processor directories/results. Only used in
// decomposePar
virtual void setNProcs(const label nProcs);
//- Get number of processor directories/results. Used for e.g.
// reconstructPar, argList checking
virtual label nProcs
@ -424,9 +492,59 @@ public:
//- Get sorted list of times
virtual instantList findTimes(const fileName&, const word&) const;
//- Find instance where IOobject is. Fails if cannot be found
// and readOpt() is MUST_READ/MUST_READ_IF_MODIFIED. Otherwise
// returns stopInstance.
virtual IOobject findInstance
(
const IOobject& io,
const scalar startValue,
const word& stopInstance
) const;
//- Callback for time change
virtual void setTime(const Time&) const
{}
//- Generate path (like io.path) from root+casename with any
// 'processorXXX' replaced by procDir (usually 'processsors')
fileName processorsCasePath
(
const IOobject&,
const word& procDir
) const;
//- Generate path (like io.path) with provided instance and any
// 'processorXXX' replaced by procDir (usually 'processsors')
fileName processorsPath
(
const IOobject&,
const word& instance,
const word& procDir
) const;
//- Operating on fileName: replace processorXXX with procDir
fileName processorsPath(const fileName&, const word& procDir) const;
//- Split fileName into part before 'processor' and part after.
// Returns -1 or processor number and optionally number
// of processors. Use with care.
// - path/"processor"+Foam::name(proci)/local reconstructs input
// - path/"processors"+Foam::name(nProcs)/local reconstructs
// collated processors equivalence
static label splitProcessorPath
(
const fileName&,
fileName& path,
fileName& procDir,
fileName& local,
label& groupStart,
label& groupSize,
label& nProcs
);
//- Detect processor number from '/aa/bb/processorDDD/cc'
static label detectProcessorPath(const fileName&);
};

View File

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fileOperationInitialise.H"
#include "addToRunTimeSelectionTable.H"
#include "OSspecific.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
namespace Foam
{
namespace fileOperations
{
defineTypeNameAndDebug(fileOperationInitialise, 0);
defineRunTimeSelectionTable(fileOperationInitialise, word);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileOperations::fileOperationInitialise::fileOperationInitialise
(
int& argc,
char**& argv
)
{}
Foam::autoPtr<Foam::fileOperations::fileOperationInitialise>
Foam::fileOperations::fileOperationInitialise::New
(
const word& type,
int& argc,
char**& argv
)
{
if (debug)
{
InfoInFunction << "Constructing fileOperationInitialise" << endl;
}
wordConstructorTable::iterator cstrIter =
wordConstructorTablePtr_->find(type);
if (cstrIter == wordConstructorTablePtr_->end())
{
FatalErrorInFunction
<< "Unknown fileOperationInitialise type "
<< type << nl << nl
<< "Valid fileOperationInitialise types are" << endl
<< wordConstructorTablePtr_->sortedToc()
<< abort(FatalError);
}
return autoPtr<fileOperationInitialise>(cstrIter()(argc, argv));
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileOperations::fileOperationInitialise::~fileOperationInitialise()
{}
// ************************************************************************* //

View File

@ -0,0 +1,102 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
Class
Foam::fileOperationInitialise
\*---------------------------------------------------------------------------*/
#ifndef fileOperationInitialise_H
#define fileOperationInitialise_H
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fileOperations
{
/*---------------------------------------------------------------------------*\
Class fileOperationInitialise Declaration
\*---------------------------------------------------------------------------*/
class fileOperationInitialise
{
public:
//- Runtime type information
TypeName("fileOperationInitialise");
// Constructors
//- Construct components
fileOperationInitialise(int& argc, char**& argv);
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
fileOperationInitialise,
word,
(
int& argc, char**& argv
),
(argc, argv)
);
// Selectors
//- Select type
static autoPtr<fileOperationInitialise> New
(
const word& type, int& argc, char**& argv
);
//- Destructor
virtual ~fileOperationInitialise();
// Member Functions
//- Needs threading
virtual bool needsThreading() const = 0;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fileOperations
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017-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 <http://www.gnu.org/licenses/>.
Class
Foam::unthreadedInitialise
\*---------------------------------------------------------------------------*/
#ifndef unthreadedInitialise_H
#define unthreadedInitialise_H
#include "fileOperationInitialise.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fileOperations
{
/*---------------------------------------------------------------------------*\
Class unthreadedInitialise Declaration
\*---------------------------------------------------------------------------*/
class unthreadedInitialise
:
public fileOperationInitialise
{
public:
// Constructors
//- Construct from components
unthreadedInitialise(int& argc, char**& argv)
:
fileOperationInitialise(argc, argv)
{}
//- Destructor
virtual ~unthreadedInitialise()
{}
// Member Functions
//- Needs threading
virtual bool needsThreading() const
{
return false;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fileOperations
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -28,6 +28,31 @@ Description
fileOperations that performs all file operations on the master processor.
Requires the calls to be parallel synchronised!
Limitations: - no /processor in filename
- no /uniform/ in the filename
The main logic is in ::filePath which returns a
- same path on all processors. This can either be a global file
(system/controlDict, processorXXX/0/uniform/) or a collated file
(processors/0/p)
- same path on all processors of the local communicator
(processors4_0-1/0/p)
- different path on all processors (processor0/0/p)
system/controlDict:
filePath worldmaster: <globalRoot>/system/controlDict
localmaster: ,,
slave : ,,
processor0/uniform/time
filePath worldmaster: <globalRoot>/processorXXX/uniform/time
localmaster: ,,
slave : ,,
processors0/0/p
processors10/0/p
processors10_2-4/0/p
\*---------------------------------------------------------------------------*/
#ifndef fileOperations_masterUncollatedFileOperation_H
@ -36,6 +61,9 @@ Description
#include "fileOperation.H"
#include "OSspecific.H"
#include "HashPtrTable.H"
#include "Switch.H"
#include "unthreadedInitialise.H"
#include "boolList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -59,6 +87,9 @@ protected:
// Protected data
//- Any communicator allocated by me
const label myComm_;
//- Cached times for a given directory
mutable HashPtrTable<instantList> times_;
@ -354,18 +385,29 @@ protected:
// Private Member Functions
//- Get the list of processors that are part of this communicator
static labelList subRanks(const label n);
template<class Type>
Type scatterList(const UList<Type>&) const;
Type scatterList(const UList<Type>&, const int, const label comm) const;
template<class Type, class fileOp>
Type masterOp(const fileName&, const fileOp& fop) const;
Type masterOp
(
const fileName&,
const fileOp& fop,
const int tag,
const label comm
) const;
template<class Type, class fileOp>
Type masterOp
(
const fileName&,
const fileName&,
const fileOp& fop
const fileOp& fop,
const int tag,
const label comm
) const;
//- Equivalent of Time::findInstance
@ -375,26 +417,32 @@ protected:
const instant& t
);
//- Search for object; return info on how it was found
//- Search (locally!) for object; return info on how it was found.
// Does not do any parallel communication.
// checkGlobal : also check undecomposed case
// isFile : true:check for file; false:check for directory
fileName filePathInfo
// isFile : true:check for file false:check for directory
// searchType : how was found
// processorsDir : name of processor directory
// instance : instance
virtual fileName filePathInfo
(
const bool checkGlobal,
const bool isFile,
const IOobject& io,
const IOobject&,
const bool search,
pathType&,
word&
pathType& searchType,
word& processorsDir,
word& instance
) const;
//- Construct filePath
static fileName objectPath
fileName localObjectPath
(
const IOobject&,
const pathType&,
const word&
);
const pathType& searchType,
const word& processorsDir,
const word& instancePath
) const;
//- Read file contents and send to processors
static void readAndSend
@ -405,6 +453,29 @@ protected:
PstreamBuffers& pBufs
);
//- Detect file (possibly compressed), read file contents and send
// to processors
static void readAndSend
(
const fileName& fName,
const labelUList& procs,
PstreamBuffers& pBufs
);
//- Read files on comms master
static autoPtr<ISstream> read
(
IOobject& io,
const label comm,
const bool uniform, // on comms master only
const fileNameList& filePaths, // on comms master only
const boolList& procValid // on comms master only
);
//- Helper: check IO for local existence. Like filePathInfo but
// without parent searchign and instance searching
bool exists(const dirIndexList&, IOobject& io) const;
public:
@ -425,9 +496,12 @@ public:
//- Construct null
masterUncollatedFileOperation(const bool verbose);
//- Construct from communicator
masterUncollatedFileOperation(const label comm, const bool verbose);
//- Destructor
virtual ~masterUncollatedFileOperation() = default;
virtual ~masterUncollatedFileOperation();
// Member Functions
@ -682,30 +756,19 @@ public:
//- Get sorted list of times
virtual instantList findTimes(const fileName&, const word&) const;
//- Find instance where IOobject is. Fails if cannot be found
// and readOpt() is MUST_READ/MUST_READ_IF_MODIFIED. Otherwise
// returns stopInstance.
virtual IOobject findInstance
(
const IOobject& io,
const scalar startValue,
const word& stopInstance
) const;
//- Callback for time change
virtual void setTime(const Time&) const;
//- root+casename with any 'processorXXX' replaced by 'processsors'
static fileName processorsCasePath(const IOobject&);
//- Like io.path with provided instance and any 'processorXXX'
// replaced by 'processsors'
static fileName processorsPath(const IOobject&, const word&);
//- Operating on fileName: replace processorXXX with processors
static fileName processorsPath(const fileName&);
//- Split fileName into part before processor and part after.
// Returns -1 or processor number. Use with care.
// - path/"processor" + Foam::name(proci)/local reconstructs input
// - path/"processors"/local reconstructs processors equivalence
static label splitProcessorPath
(
const fileName&,
fileName& path,
fileName& local
);
//- Return cached times
const HashPtrTable<instantList>& times() const
{
@ -714,6 +777,28 @@ public:
};
/*---------------------------------------------------------------------------*\
Class masterUncollatedFileOperationInitialise Declaration
\*---------------------------------------------------------------------------*/
class masterUncollatedFileOperationInitialise
:
public unthreadedInitialise
{
public:
// Constructors
//- Construct from components
masterUncollatedFileOperationInitialise(int& argc, char**& argv);
//- Destructor
virtual ~masterUncollatedFileOperationInitialise()
{}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fileOperations

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2017-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -31,14 +31,16 @@ License
template<class Type>
Type Foam::fileOperations::masterUncollatedFileOperation::scatterList
(
const UList<Type>& masterLst
const UList<Type>& masterLst,
const int tag,
const label comm
) const
{
// TBD: more efficient scatter
PstreamBuffers pBufs(UPstream::commsTypes::nonBlocking);
if (Pstream::master())
PstreamBuffers pBufs(UPstream::commsTypes::nonBlocking, tag, comm);
if (Pstream::master(comm))
{
for (label proci = 1; proci < Pstream::nProcs(); proci++)
for (label proci = 1; proci < Pstream::nProcs(comm); proci++)
{
UOPstream os(proci, pBufs);
os << masterLst[proci];
@ -48,9 +50,9 @@ Type Foam::fileOperations::masterUncollatedFileOperation::scatterList
Type myResult;
if (Pstream::master())
if (Pstream::master(comm))
{
myResult = masterLst[Pstream::myProcNo()];
myResult = masterLst[Pstream::myProcNo(comm)];
}
else
{
@ -65,21 +67,25 @@ template<class Type, class fileOp>
Type Foam::fileOperations::masterUncollatedFileOperation::masterOp
(
const fileName& fName,
const fileOp& fop
const fileOp& fop,
const int tag,
const label comm
) const
{
if (IFstream::debug)
{
Pout<< "masterUncollatedFileOperation : Operation on " << fName << endl;
Pout<< "masterUncollatedFileOperation::masterOp : Operation "
<< typeid(fileOp).name()
<< " on " << fName << endl;
}
if (Pstream::parRun())
{
List<fileName> filePaths(Pstream::nProcs());
filePaths[Pstream::myProcNo()] = fName;
Pstream::gatherList(filePaths);
List<fileName> filePaths(Pstream::nProcs(comm));
filePaths[Pstream::myProcNo(comm)] = fName;
Pstream::gatherList(filePaths, tag, comm);
List<Type> result(Pstream::nProcs());
if (Pstream::master())
List<Type> result(filePaths.size());
if (Pstream::master(comm))
{
result = fop(filePaths[0]);
for (label i = 1; i < filePaths.size(); i++)
@ -91,7 +97,7 @@ Type Foam::fileOperations::masterUncollatedFileOperation::masterOp
}
}
return scatterList(result);
return scatterList(result, tag, comm);
}
else
{
@ -105,7 +111,9 @@ Type Foam::fileOperations::masterUncollatedFileOperation::masterOp
(
const fileName& src,
const fileName& dest,
const fileOp& fop
const fileOp& fop,
const int tag,
const label comm
) const
{
if (IFstream::debug)
@ -115,16 +123,16 @@ Type Foam::fileOperations::masterUncollatedFileOperation::masterOp
}
if (Pstream::parRun())
{
List<fileName> srcs(Pstream::nProcs());
srcs[Pstream::myProcNo()] = src;
Pstream::gatherList(srcs);
List<fileName> srcs(Pstream::nProcs(comm));
srcs[Pstream::myProcNo(comm)] = src;
Pstream::gatherList(srcs, tag, comm);
List<fileName> dests(Pstream::nProcs());
dests[Pstream::myProcNo()] = dest;
Pstream::gatherList(dests);
List<fileName> dests(srcs.size());
dests[Pstream::myProcNo(comm)] = dest;
Pstream::gatherList(dests, tag, comm);
List<Type> result(Pstream::nProcs());
if (Pstream::master())
List<Type> result(Pstream::nProcs(comm));
if (Pstream::master(comm))
{
result = fop(srcs[0], dests[0]);
for (label i = 1; i < srcs.size(); i++)
@ -136,7 +144,7 @@ Type Foam::fileOperations::masterUncollatedFileOperation::masterOp
}
}
return scatterList(result);
return scatterList(result, tag, comm);
}
else
{

View File

@ -27,9 +27,9 @@ License
#include "Time.H"
#include "Fstream.H"
#include "addToRunTimeSelectionTable.H"
#include "masterUncollatedFileOperation.H"
#include "decomposedBlockData.H"
#include "dummyISstream.H"
#include "unthreadedInitialise.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
@ -39,6 +39,15 @@ namespace fileOperations
{
defineTypeNameAndDebug(uncollatedFileOperation, 0);
addToRunTimeSelectionTable(fileOperation, uncollatedFileOperation, word);
// Mark as not needing threaded mpi
addNamedToRunTimeSelectionTable
(
fileOperationInitialise,
unthreadedInitialise,
word,
uncollated
);
}
}
@ -102,17 +111,20 @@ Foam::fileName Foam::fileOperations::uncollatedFileOperation::filePathInfo
// Check if parallel "procesors" directory
if (io.time().processorCase())
{
fileName path = fileOperations::masterUncollatedFileOperation::
processorsPath
tmpNrc<dirIndexList> pDirs
(
io,
io.instance()
lookupProcessorsPath(io.objectPath())
);
fileName objectPath = path/io.name();
if (isFileOrDir(isFile, objectPath))
forAll(pDirs(), i)
{
return objectPath;
const fileName& pDir = pDirs()[i].first();
fileName objPath =
processorsPath(io, io.instance(), pDir)
/io.name();
if (objPath != objectPath && isFileOrDir(isFile, objPath))
{
return objPath;
}
}
}
@ -153,6 +165,8 @@ Foam::fileOperations::uncollatedFileOperation::uncollatedFileOperation
(
const bool verbose
)
:
fileOperation(Pstream::worldComm)
{
if (verbose)
{
@ -533,15 +547,7 @@ Foam::fileOperations::uncollatedFileOperation::readStream
{
// Analyse the objectpath to find out the processor we're trying
// to access
fileName path;
fileName local;
label proci = fileOperations::masterUncollatedFileOperation::
splitProcessorPath
(
io.objectPath(),
path,
local
);
label proci = detectProcessorPath(io.objectPath());
if (proci == -1)
{
@ -551,6 +557,26 @@ Foam::fileOperations::uncollatedFileOperation::readStream
<< exit(FatalIOError);
}
// Analyse the fileName for any processor subset. Note: this
// should really be part of filePath() which should return
// both file and index in file.
fileName path, procDir, local;
label groupStart, groupSize, nProcs;
splitProcessorPath
(
fName,
path,
procDir,
local,
groupStart,
groupSize,
nProcs
);
if (groupStart != -1 && groupSize > 0)
{
proci = proci-groupStart;
}
// Read data and return as stream
return decomposedBlockData::readBlock(proci, isPtr(), io);
}
@ -570,8 +596,8 @@ bool Foam::fileOperations::uncollatedFileOperation::read
{
if (debug)
{
Pout<< "uncollatedFileOperation::read() : "
<< "reading object " << io.objectPath()
Pout<< "uncollatedFileOperation::read :"
<< " Reading object " << io.objectPath()
<< " from file " << endl;
}

View File

@ -256,33 +256,6 @@ bool dlSymFound(void* handle, const std::string& symbol);
fileNameList dlLoaded();
// Thread handling
//- Allocate a thread
label allocateThread();
//- Start a thread
void createThread(const label, void *(*start_routine) (void *), void *arg);
//- Wait for thread
void joinThread(const label);
//- Delete a thread
void freeThread(const label);
//- Allocate a mutex variable
label allocateMutex();
//- Lock a mutex variable
void lockMutex(const label);
//- Unlock a mutex variable
void unlockMutex(const label);
//- Free a mutex variable
void freeMutex(const label);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -67,7 +67,7 @@ class tmpNrc
mutable T* ptr_;
//- The type (managed pointer | const-reference object)
refType type_;
mutable refType type_;
public:
@ -160,6 +160,9 @@ public:
//- delete object and set pointer to nullptr
inline void clear() const;
//- Swaps the managed object with other tmpNrc.
inline void swap(tmpNrc<T>& other) noexcept;
// Member operators

View File

@ -266,7 +266,7 @@ Foam::faceZone::faceZone
(
const word& name,
const labelUList& addr,
const boolList& fm,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
)
@ -328,7 +328,7 @@ Foam::faceZone::faceZone
(
const faceZone& origZone,
const labelUList& addr,
const boolList& fm,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
)
@ -468,7 +468,7 @@ void Foam::faceZone::resetAddressing
void Foam::faceZone::resetAddressing
(
const labelUList& addr,
const boolList& flipMap
const boolUList& flipMap
)
{
clearAddressing();

View File

@ -177,7 +177,7 @@ public:
(
const word& name,
const labelUList& addr,
const boolList& fm,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
);
@ -208,7 +208,7 @@ public:
(
const faceZone& origZone,
const labelUList& addr,
const boolList& fm,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
);
@ -236,7 +236,7 @@ public:
virtual autoPtr<faceZone> clone
(
const labelUList& addr,
const boolList& fm,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
) const
@ -309,7 +309,7 @@ public:
virtual void resetAddressing
(
const labelUList& addr,
const boolList& flipMap
const boolUList& flipMap
);
//- Move reset addressing - use uniform flip map value

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -42,7 +42,7 @@ bool Foam::UPstream::initNull()
}
bool Foam::UPstream::init(int& argc, char**& argv)
bool Foam::UPstream::init(int& argc, char**& argv, const bool needsThread)
{
FatalErrorInFunction
<< "The dummy Pstream library cannot be used in parallel mode"

View File

@ -1,5 +1,5 @@
sinclude $(GENERAL_RULES)/mplib$(WM_MPLIB)
sinclude $(RULES)/mplib$(WM_MPLIB)
sinclude $(DEFAULT_RULES)/mplib$(WM_MPLIB)
EXE_INC = $(PFLAGS) $(PINC) $(c++LESSWARN)
LIB_LIBS = $(PLIBS)

View File

@ -101,7 +101,7 @@ bool Foam::UPstream::initNull()
}
bool Foam::UPstream::init(int& argc, char**& argv)
bool Foam::UPstream::init(int& argc, char**& argv, const bool needsThread)
{
int flag = 0;
@ -129,17 +129,16 @@ bool Foam::UPstream::init(int& argc, char**& argv)
//MPI_Init(&argc, &argv);
int wanted_thread_support = MPI_THREAD_SINGLE;
if (fileOperations::collatedFileOperation::maxThreadFileBufferSize > 0)
{
wanted_thread_support = MPI_THREAD_MULTIPLE;
}
int provided_thread_support;
MPI_Init_thread
(
&argc,
&argv,
wanted_thread_support,
(
needsThread
? MPI_THREAD_MULTIPLE
: MPI_THREAD_SINGLE
),
&provided_thread_support
);

View File

@ -571,7 +571,8 @@ void Foam::vtk::vtuSizing::populateArrays
if (output == contentType::LEGACY)
{
// Update size for legacy face stream
faceOutput[startLabel] = (faceIndexer - startLabel);
// (subtract 1 to avoid counting the storage location)
faceOutput[startLabel] = (faceIndexer - 1 - startLabel);
}
else
{

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015-2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -42,6 +42,7 @@ License
#include "fvMeshTools.H"
#include "labelPairHashes.H"
#include "ListOps.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -688,25 +689,54 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::fvMeshDistribute::repatch
// merge those points.
Foam::autoPtr<Foam::mapPolyMesh> Foam::fvMeshDistribute::mergeSharedPoints
(
const labelList& pointToGlobalMaster,
labelListList& constructPointMap
)
{
// Find out which sets of points get merged and create a map from
// mesh point to unique point.
Map<label> pointToMaster
(
fvMeshAdder::findSharedPoints
(
mesh_,
mergeTol_
)
);
label nShared = 0;
forAll(pointToGlobalMaster, pointi)
{
if (pointToGlobalMaster[pointi] != -1)
{
nShared++;
}
}
Map<label> globalMasterToLocalMaster(2*nShared);
Map<label> pointToMaster(2*nShared);
forAll(pointToGlobalMaster, pointi)
{
label globali = pointToGlobalMaster[pointi];
if (globali != -1)
{
Map<label>::const_iterator iter = globalMasterToLocalMaster.find
(
globali
);
if (iter == globalMasterToLocalMaster.end())
{
// Found first point. Designate as master
globalMasterToLocalMaster.insert(globali, pointi);
pointToMaster.insert(pointi, pointi);
}
else
{
pointToMaster.insert(pointi, iter());
}
}
}
if (returnReduce(pointToMaster.size(), sumOp<label>()) == 0)
{
return nullptr;
}
polyTopoChange meshMod(mesh_);
fvMeshAdder::mergePoints(mesh_, pointToMaster, meshMod);
@ -750,16 +780,19 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::fvMeshDistribute::mergeSharedPoints
}
// Construct the local environment of all boundary faces.
void Foam::fvMeshDistribute::getNeighbourData
void Foam::fvMeshDistribute::getCouplingData
(
const labelList& distribution,
labelList& sourceFace,
labelList& sourceProc,
labelList& sourcePatch,
labelList& sourceNewNbrProc
labelList& sourceNewNbrProc,
labelList& sourcePointMaster
) const
{
// Construct the coupling information for all (boundary) faces and
// points
label nBnd = mesh_.nFaces() - mesh_.nInternalFaces();
sourceFace.setSize(nBnd);
sourceProc.setSize(nBnd);
@ -890,13 +923,62 @@ void Foam::fvMeshDistribute::getNeighbourData
}
}
}
// Collect coupled (collocated) points
sourcePointMaster.setSize(mesh_.nPoints());
sourcePointMaster = -1;
{
// Assign global master point
const globalIndex globalPoints(mesh_.nPoints());
const globalMeshData& gmd = mesh_.globalData();
const indirectPrimitivePatch& cpp = gmd.coupledPatch();
const labelList& meshPoints = cpp.meshPoints();
const mapDistribute& slavesMap = gmd.globalCoPointSlavesMap();
const labelListList& slaves = gmd.globalCoPointSlaves();
labelList elems(slavesMap.constructSize(), -1);
forAll(meshPoints, pointi)
{
const labelList& slots = slaves[pointi];
if (slots.size())
{
// pointi is a master. Assign a unique label.
label globalPointi = globalPoints.toGlobal(meshPoints[pointi]);
elems[pointi] = globalPointi;
forAll(slots, i)
{
label sloti = slots[i];
if (sloti >= meshPoints.size())
{
// Filter out local collocated points. We don't want
// to merge these
elems[slots[i]] = globalPointi;
}
}
}
}
// Push slave-slot data back to slaves
slavesMap.reverseDistribute(elems.size(), elems, false);
// Extract back onto mesh
forAll(meshPoints, pointi)
{
sourcePointMaster[meshPoints[pointi]] = elems[pointi];
}
}
}
// Subset the neighbourCell/neighbourProc fields
void Foam::fvMeshDistribute::subsetBoundaryData
void Foam::fvMeshDistribute::subsetCouplingData
(
const fvMesh& mesh,
const labelList& pointMap,
const labelList& faceMap,
const labelList& cellMap,
@ -909,11 +991,13 @@ void Foam::fvMeshDistribute::subsetBoundaryData
const labelList& sourceProc,
const labelList& sourcePatch,
const labelList& sourceNewNbrProc,
const labelList& sourcePointMaster,
labelList& subFace,
labelList& subProc,
labelList& subPatch,
labelList& subNewNbrProc
labelList& subNewNbrProc,
labelList& subPointMaster
)
{
subFace.setSize(mesh.nFaces() - mesh.nInternalFaces());
@ -959,6 +1043,9 @@ void Foam::fvMeshDistribute::subsetBoundaryData
subNewNbrProc[newBFacei] = sourceNewNbrProc[oldBFacei];
}
}
subPointMaster = UIndirectList<label>(sourcePointMaster, pointMap);
}
@ -1042,9 +1129,9 @@ Foam::labelList Foam::fvMeshDistribute::mapBoundaryData
(
const primitiveMesh& mesh, // mesh after adding
const mapAddedPolyMesh& map,
const labelList& boundaryData0, // mesh before adding
const labelList& boundaryData0, // on mesh before adding
const label nInternalFaces1,
const labelList& boundaryData1 // added mesh
const labelList& boundaryData1 // on added mesh
)
{
labelList newBoundaryData(mesh.nFaces() - mesh.nInternalFaces());
@ -1076,6 +1163,41 @@ Foam::labelList Foam::fvMeshDistribute::mapBoundaryData
}
Foam::labelList Foam::fvMeshDistribute::mapPointData
(
const primitiveMesh& mesh, // mesh after adding
const mapAddedPolyMesh& map,
const labelList& boundaryData0, // on mesh before adding
const labelList& boundaryData1 // on added mesh
)
{
labelList newBoundaryData(mesh.nPoints());
forAll(boundaryData0, oldPointi)
{
label newPointi = map.oldPointMap()[oldPointi];
// Point still exists (is necessary?)
if (newPointi >= 0)
{
newBoundaryData[newPointi] = boundaryData0[oldPointi];
}
}
forAll(boundaryData1, addedPointi)
{
label newPointi = map.addedPointMap()[addedPointi];
if (newPointi >= 0)
{
newBoundaryData[newPointi] = boundaryData1[addedPointi];
}
}
return newBoundaryData;
}
// Remove cells. Add all exposed faces to patch oldInternalPatchi
Foam::autoPtr<Foam::mapPolyMesh> Foam::fvMeshDistribute::doRemoveCells
(
@ -1297,6 +1419,7 @@ void Foam::fvMeshDistribute::sendMesh
const labelList& sourceProc,
const labelList& sourcePatch,
const labelList& sourceNewNbrProc,
const labelList& sourcePointMaster,
Ostream& toDomain
)
{
@ -1433,7 +1556,8 @@ void Foam::fvMeshDistribute::sendMesh
<< sourceFace
<< sourceProc
<< sourcePatch
<< sourceNewNbrProc;
<< sourceNewNbrProc
<< sourcePointMaster;
if (debug)
@ -1456,6 +1580,7 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshDistribute::receiveMesh
labelList& domainSourceProc,
labelList& domainSourcePatch,
labelList& domainSourceNewNbrProc,
labelList& domainSourcePointMaster,
Istream& fromNbr
)
{
@ -1474,7 +1599,8 @@ Foam::autoPtr<Foam::fvMesh> Foam::fvMeshDistribute::receiveMesh
>> domainSourceFace
>> domainSourceProc
>> domainSourcePatch
>> domainSourceNewNbrProc;
>> domainSourceNewNbrProc
>> domainSourcePointMaster;
// Construct fvMesh
auto domainMeshPtr = autoPtr<fvMesh>::New
@ -1709,13 +1835,15 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
labelList sourceFace;
labelList sourceProc;
labelList sourceNewNbrProc;
getNeighbourData
labelList sourcePointMaster;
getCouplingData
(
distribution,
sourceFace,
sourceProc,
sourcePatch,
sourceNewNbrProc
sourceNewNbrProc,
sourcePointMaster
);
@ -1924,11 +2052,13 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
labelList procSourceProc;
labelList procSourcePatch;
labelList procSourceNewNbrProc;
labelList procSourcePointMaster;
subsetBoundaryData
subsetCouplingData
(
subsetter.subMesh(),
subsetter.faceMap(), // from subMesh to mesh
subsetter.pointMap(), // from subMesh to mesh
subsetter.faceMap(), // ,, ,,
subsetter.cellMap(), // ,, ,,
distribution, // old mesh distribution
@ -1940,15 +2070,16 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
sourceProc,
sourcePatch,
sourceNewNbrProc,
sourcePointMaster,
procSourceFace,
procSourceProc,
procSourcePatch,
procSourceNewNbrProc
procSourceNewNbrProc,
procSourcePointMaster
);
// Send to neighbour
sendMesh
(
@ -1963,6 +2094,8 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
procSourceProc,
procSourcePatch,
procSourceNewNbrProc,
procSourcePointMaster,
str
);
@ -2121,10 +2254,12 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
labelList domainSourceProc;
labelList domainSourcePatch;
labelList domainSourceNewNbrProc;
labelList domainSourcePointMaster;
subsetBoundaryData
subsetCouplingData
(
mesh_, // new mesh
subMap().pointMap(), // from new to original mesh
subMap().faceMap(), // from new to original mesh
subMap().cellMap(),
@ -2137,17 +2272,20 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
sourceProc,
sourcePatch,
sourceNewNbrProc,
sourcePointMaster,
domainSourceFace,
domainSourceProc,
domainSourcePatch,
domainSourceNewNbrProc
domainSourceNewNbrProc,
domainSourcePointMaster
);
sourceFace.transfer(domainSourceFace);
sourceProc.transfer(domainSourceProc);
sourcePatch.transfer(domainSourcePatch);
sourceNewNbrProc.transfer(domainSourceNewNbrProc);
sourcePointMaster.transfer(domainSourcePointMaster);
}
@ -2205,6 +2343,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
labelList domainSourceProc;
labelList domainSourcePatch;
labelList domainSourceNewNbrProc;
labelList domainSourcePointMaster;
autoPtr<fvMesh> domainMeshPtr;
@ -2241,6 +2380,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
domainSourceProc,
domainSourcePatch,
domainSourceNewNbrProc,
domainSourcePointMaster,
str
);
fvMesh& domainMesh = domainMeshPtr();
@ -2508,6 +2648,15 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
domainMesh.nInternalFaces(),
domainSourceNewNbrProc
);
// Update pointMaster data
sourcePointMaster = mapPointData
(
mesh_,
map(),
sourcePointMaster,
domainSourcePointMaster
);
// Update all addressing so xxProcAddressing points to correct
// item in masterMesh.
@ -2621,6 +2770,10 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
}
// See if any originally shared points need to be merged. Note: does
// parallel comms. After this points and edges should again be consistent.
mergeSharedPoints(sourcePointMaster, constructPointMap);
// Add processorPatches
// ~~~~~~~~~~~~~~~~~~~~
@ -2650,16 +2803,8 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::fvMeshDistribute::distribute
// Change patches. Since this might change ordering of coupled faces
// we also need to adapt our constructMaps.
// NOTE: there is one very particular problem with this structure.
// We first create the processor patches and use these to merge out
// shared points (see mergeSharedPoints below). So temporarily points
// and edges do not match!
repatch(newPatchID, constructFaceMap);
// See if any geometrically shared points need to be merged. Note: does
// parallel comms. After this points and edges should again be consistent.
mergeSharedPoints(constructPointMap);
// Bit of hack: processorFvPatchField does not get reset since created
// from nothing so explicitly reset.
initPatchFields<volScalarField, processorFvPatchField<scalar>>

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -163,11 +163,11 @@ class fvMeshDistribute
labelListList& constructFaceMap
);
//- Merge any shared points that are geometrically shared. Needs
// parallel valid mesh - uses globalMeshData.
//- Merge any local points that were remotely coupled.
// constructPointMap is adapted for the new point labels.
autoPtr<mapPolyMesh> mergeSharedPoints
(
const labelList& pointToGlobalMaster,
labelListList& constructPointMap
);
@ -175,19 +175,21 @@ class fvMeshDistribute
// Coupling information
//- Construct the local environment of all boundary faces.
void getNeighbourData
void getCouplingData
(
const labelList& distribution,
labelList& sourceFace,
labelList& sourceProc,
labelList& sourcePatch,
labelList& sourceNewProc
labelList& sourceNewProc,
labelList& sourcePointMaster
) const;
// Subset the neighbourCell/neighbourProc fields
static void subsetBoundaryData
static void subsetCouplingData
(
const fvMesh& mesh,
const labelList& pointMap,
const labelList& faceMap,
const labelList& cellMap,
@ -200,11 +202,13 @@ class fvMeshDistribute
const labelList& sourceProc,
const labelList& sourcePatch,
const labelList& sourceNewProc,
const labelList& sourcePointMaster,
labelList& subFace,
labelList& subProc,
labelList& subPatch,
labelList& subNewProc
labelList& subNewProc,
labelList& subPointMaster
);
//- Find cells on mesh whose faceID/procID match the neighbour
@ -237,6 +241,14 @@ class fvMeshDistribute
const labelList& boundaryData1 // added mesh
);
//- Map point data to new mesh (resulting from adding two meshes)
static labelList mapPointData
(
const primitiveMesh& mesh, // mesh after adding
const mapAddedPolyMesh& map,
const labelList& boundaryData0, // on mesh before adding
const labelList& boundaryData1 // on added mesh
);
// Other
@ -276,6 +288,7 @@ class fvMeshDistribute
const labelList& sourceProc,
const labelList& sourcePatch,
const labelList& sourceNewProc,
const labelList& sourcePointMaster,
Ostream& toDomain
);
//- Send subset of fields
@ -300,6 +313,7 @@ class fvMeshDistribute
labelList& domainSourceProc,
labelList& domainSourcePatch,
labelList& domainSourceNewProc,
labelList& domainSourcePointMaster,
Istream& fromNbr
);

View File

@ -154,6 +154,7 @@ $(derivedFvPatchFields)/flowRateInletVelocity/flowRateInletVelocityFvPatchVector
$(derivedFvPatchFields)/flowRateOutletVelocity/flowRateOutletVelocityFvPatchVectorField.C
$(derivedFvPatchFields)/fluxCorrectedVelocity/fluxCorrectedVelocityFvPatchVectorField.C
$(derivedFvPatchFields)/freestream/freestreamFvPatchFields.C
$(derivedFvPatchFields)/freestreamVelocity/freestreamVelocityFvPatchVectorField.C
$(derivedFvPatchFields)/freestreamPressure/freestreamPressureFvPatchScalarField.C
$(derivedFvPatchFields)/inletOutlet/inletOutletFvPatchFields.C
$(derivedFvPatchFields)/inletOutletTotalTemperature/inletOutletTotalTemperatureFvPatchScalarField.C
@ -168,6 +169,7 @@ $(derivedFvPatchFields)/noSlip/noSlipFvPatchVectorField.C
$(derivedFvPatchFields)/movingWallVelocity/movingWallVelocityFvPatchVectorField.C
$(derivedFvPatchFields)/outletInlet/outletInletFvPatchFields.C
$(derivedFvPatchFields)/outletMappedUniformInlet/outletMappedUniformInletFvPatchFields.C
$(derivedFvPatchFields)/fixedMeanOutletInlet/fixedMeanOutletInletFvPatchFields.C
$(derivedFvPatchFields)/partialSlip/partialSlipFvPatchFields.C
$(derivedFvPatchFields)/phaseHydrostaticPressure/phaseHydrostaticPressureFvPatchScalarField.C
$(derivedFvPatchFields)/pressureDirectedInletOutletVelocity/pressureDirectedInletOutletVelocityFvPatchVectorField.C

View File

@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fixedMeanOutletInletFvPatchField.H"
#include "volFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::fixedMeanOutletInletFvPatchField<Type>::fixedMeanOutletInletFvPatchField
(
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF
)
:
outletInletFvPatchField<Type>(p, iF),
meanValue_()
{}
template<class Type>
Foam::fixedMeanOutletInletFvPatchField<Type>::fixedMeanOutletInletFvPatchField
(
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF,
const dictionary& dict
)
:
outletInletFvPatchField<Type>(p, iF),
meanValue_(Function1<Type>::New("meanValue", dict))
{
this->phiName_ = dict.lookupOrDefault<word>("phi", "phi");
fvPatchField<Type>::operator=
(
Field<Type>("value", dict, p.size())
);
this->refValue() = *this;
this->refGrad() = Zero;
this->valueFraction() = 0.0;
}
template<class Type>
Foam::fixedMeanOutletInletFvPatchField<Type>::fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>& ptf,
const fvPatch& p,
const DimensionedField<Type, volMesh>& iF,
const fvPatchFieldMapper& mapper
)
:
outletInletFvPatchField<Type>(ptf, p, iF, mapper),
meanValue_(ptf.meanValue_.clone())
{}
template<class Type>
Foam::fixedMeanOutletInletFvPatchField<Type>::fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>& ptf
)
:
outletInletFvPatchField<Type>(ptf),
meanValue_(ptf.meanValue_.clone())
{}
template<class Type>
Foam::fixedMeanOutletInletFvPatchField<Type>::fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>& ptf,
const DimensionedField<Type, volMesh>& iF
)
:
outletInletFvPatchField<Type>(ptf, iF),
meanValue_(ptf.meanValue_.clone())
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::fixedMeanOutletInletFvPatchField<Type>::updateCoeffs()
{
if (this->updated())
{
return;
}
const scalar t = this->db().time().timeOutputValue();
Type meanValue = meanValue_->value(t);
Field<Type> newValues(this->patchInternalField());
Type meanValuePsi =
gSum(this->patch().magSf()*newValues)
/gSum(this->patch().magSf());
if (mag(meanValue) > SMALL && mag(meanValuePsi)/mag(meanValue) > 0.5)
{
newValues *= mag(meanValue)/mag(meanValuePsi);
}
else
{
newValues += (meanValue - meanValuePsi);
}
this->refValue() = newValues;
outletInletFvPatchField<Type>::updateCoeffs();
}
template<class Type>
void Foam::fixedMeanOutletInletFvPatchField<Type>::write(Ostream& os) const
{
fvPatchField<Type>::write(os);
meanValue_->writeData(os);
this->writeEntry("value", os);
}
// ************************************************************************* //

View File

@ -0,0 +1,185 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::fixedMeanOutletInletFvPatchField
Group
grpInletBoundaryConditions
Description
This boundary condition extrapolates field to the patch using the near-cell
values and adjusts the distribution to match the specified, optionally
time-varying, mean value. This extrapolated field is applied as a
fixedValue for outflow faces but zeroGradient is applied to inflow faces.
This boundary condition can be applied to pressure when inletOutlet is
applied to the velocity so that a zeroGradient condition is applied to the
pressure at inflow faces where the velocity is specified to avoid an
unphysical over-specification of the set of boundary conditions.
Usage
\table
Property | Description | Required | Default value
meanValue | mean value Function1 | yes |
phi | Flux field name | no | phi
\endtable
Example of the boundary condition specification:
\verbatim
<patchName>
{
type fixedMeanOutletInlet;
meanValue 1.0;
}
\endverbatim
See also
Foam::fixedMeanFvPatchField
Foam::outletInletFvPatchField
Foam::Function1Types
SourceFiles
fixedMeanOutletInletFvPatchField.C
\*---------------------------------------------------------------------------*/
#ifndef fixedMeanOutletInletFvPatchField_H
#define fixedMeanOutletInletFvPatchField_H
#include "outletInletFvPatchFields.H"
#include "Function1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class fixedMeanOutletInletFvPatchField Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
class fixedMeanOutletInletFvPatchField
:
public outletInletFvPatchField<Type>
{
// Private data
//- MeanValue value the field is adjusted to maintain
autoPtr<Function1<Type>> meanValue_;
public:
//- Runtime type information
TypeName("fixedMeanOutletInlet");
// Constructors
//- Construct from patch and internal field
fixedMeanOutletInletFvPatchField
(
const fvPatch&,
const DimensionedField<Type, volMesh>&
);
//- Construct from patch, internal field and dictionary
fixedMeanOutletInletFvPatchField
(
const fvPatch&,
const DimensionedField<Type, volMesh>&,
const dictionary&
);
//- Construct by mapping given fixedMeanOutletInletFvPatchField
// onto a new patch
fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>&,
const fvPatch&,
const DimensionedField<Type, volMesh>&,
const fvPatchFieldMapper&
);
//- Construct as copy
fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>&
);
//- Construct and return a clone
virtual tmp<fvPatchField<Type>> clone() const
{
return tmp<fvPatchField<Type>>
(
new fixedMeanOutletInletFvPatchField<Type>(*this)
);
}
//- Construct as copy setting internal field reference
fixedMeanOutletInletFvPatchField
(
const fixedMeanOutletInletFvPatchField<Type>&,
const DimensionedField<Type, volMesh>&
);
//- Construct and return a clone setting internal field reference
virtual tmp<fvPatchField<Type>> clone
(
const DimensionedField<Type, volMesh>& iF
) const
{
return tmp<fvPatchField<Type>>
(
new fixedMeanOutletInletFvPatchField<Type>(*this, iF)
);
}
// Member functions
//- Update the coefficients associated with the patch field
virtual void updateCoeffs();
//- Write
virtual void write(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "fixedMeanOutletInletFvPatchField.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "fixedMeanOutletInletFvPatchFields.H"
#include "volMesh.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
makePatchFields(fixedMeanOutletInlet);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef fixedMeanOutletInletFvPatchFields_H
#define fixedMeanOutletInletFvPatchFields_H
#include "fixedMeanOutletInletFvPatchField.H"
#include "fieldTypes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makePatchTypeFieldTypedefs(fixedMeanOutletInlet);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#ifndef fixedMeanOutletInletFvPatchFieldsFwd_H
#define fixedMeanOutletInletFvPatchFieldsFwd_H
#include "fieldTypes.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type> class fixedMeanOutletInletFvPatchField;
makePatchTypeFieldTypedefs(fixedMeanOutletInlet);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -45,7 +45,7 @@ Usage
<patchName>
{
type freestream;
phi phi;
freestreamValue uniform (300 0 0);
}
\endverbatim

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -24,10 +24,7 @@ License
\*---------------------------------------------------------------------------*/
#include "freestreamPressureFvPatchScalarField.H"
#include "freestreamFvPatchFields.H"
#include "fvPatchFieldMapper.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -39,10 +36,8 @@ freestreamPressureFvPatchScalarField
const DimensionedField<scalar, volMesh>& iF
)
:
zeroGradientFvPatchScalarField(p, iF),
UName_("U"),
phiName_("phi"),
rhoName_("rho")
mixedFvPatchScalarField(p, iF),
UName_("U")
{}
@ -54,11 +49,26 @@ freestreamPressureFvPatchScalarField
const dictionary& dict
)
:
zeroGradientFvPatchScalarField(p, iF, dict),
UName_(dict.lookupOrDefault<word>("U", "U")),
phiName_(dict.lookupOrDefault<word>("phi", "phi")),
rhoName_(dict.lookupOrDefault<word>("rho", "rho"))
{}
mixedFvPatchScalarField(p, iF),
UName_(dict.lookupOrDefault<word>("U", "U"))
{
freestreamValue() = scalarField("freestreamValue", dict, p.size());
if (dict.found("value"))
{
fvPatchScalarField::operator=
(
scalarField("value", dict, p.size())
);
}
else
{
fvPatchScalarField::operator=(freestreamValue());
}
refGrad() = Zero;
valueFraction() = 0;
}
Foam::freestreamPressureFvPatchScalarField::
@ -70,10 +80,8 @@ freestreamPressureFvPatchScalarField
const fvPatchFieldMapper& mapper
)
:
zeroGradientFvPatchScalarField(ptf, p, iF, mapper),
UName_(ptf.UName_),
phiName_(ptf.phiName_),
rhoName_(ptf.rhoName_)
mixedFvPatchScalarField(ptf, p, iF, mapper),
UName_(ptf.UName_)
{}
@ -83,10 +91,8 @@ freestreamPressureFvPatchScalarField
const freestreamPressureFvPatchScalarField& wbppsf
)
:
zeroGradientFvPatchScalarField(wbppsf),
UName_(wbppsf.UName_),
phiName_(wbppsf.phiName_),
rhoName_(wbppsf.rhoName_)
mixedFvPatchScalarField(wbppsf),
UName_(wbppsf.UName_)
{}
@ -97,10 +103,8 @@ freestreamPressureFvPatchScalarField
const DimensionedField<scalar, volMesh>& iF
)
:
zeroGradientFvPatchScalarField(wbppsf, iF),
UName_(wbppsf.UName_),
phiName_(wbppsf.phiName_),
rhoName_(wbppsf.rhoName_)
mixedFvPatchScalarField(wbppsf, iF),
UName_(wbppsf.UName_)
{}
@ -113,43 +117,15 @@ void Foam::freestreamPressureFvPatchScalarField::updateCoeffs()
return;
}
const freestreamFvPatchVectorField& Up =
refCast<const freestreamFvPatchVectorField>
const Field<vector>& Up =
patch().template lookupPatchField<volVectorField, vector>
(
patch().lookupPatchField<volVectorField, vector>(UName_)
UName_
);
const surfaceScalarField& phi =
db().lookupObject<surfaceScalarField>(phiName_);
valueFraction() = 0.5 + 0.5*(Up & patch().nf())/mag(Up);
fvsPatchField<scalar>& phip =
const_cast<fvsPatchField<scalar>&>
(
patch().patchField<surfaceScalarField, scalar>(phi)
);
if (phi.dimensions() == dimVelocity*dimArea)
{
phip = patch().Sf() & Up.freestreamValue();
}
else if (phi.dimensions() == dimDensity*dimVelocity*dimArea)
{
const fvPatchField<scalar>& rhop =
patch().lookupPatchField<volScalarField, scalar>(rhoName_);
phip = rhop*(patch().Sf() & Up.freestreamValue());
}
else
{
FatalErrorInFunction
<< "dimensions of phi are not correct"
<< "\n on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< exit(FatalError);
}
zeroGradientFvPatchScalarField::updateCoeffs();
mixedFvPatchField<scalar>::updateCoeffs();
}
@ -157,8 +133,7 @@ void Foam::freestreamPressureFvPatchScalarField::write(Ostream& os) const
{
fvPatchScalarField::write(os);
os.writeEntryIfDifferent<word>("U", "U", UName_);
os.writeEntryIfDifferent<word>("phi", "phi", phiName_);
os.writeEntryIfDifferent<word>("rho", "rho", rhoName_);
freestreamValue().writeEntry("freestreamValue", os);
writeEntry("value", os);
}

View File

@ -29,15 +29,16 @@ Group
Description
This boundary condition provides a free-stream condition for pressure.
It is a zero-gradient condition that constrains the flux across the patch
based on the free-stream velocity.
It is an outlet-inlet condition that uses the velocity orientation to
continuously blend between zero gradient for normal inlet and fixed value
for normal outlet flow.
Usage
\table
Property | Description | Required | Default value
U | velocity field name | no | U
phi | flux field name | no | phi
rho | density field name | no | none
Property | Description | Required | Default value
U | velocity field name | no | U
freestreamValue | freestream pressure | yes |
\endtable
Example of the boundary condition specification:
@ -45,14 +46,15 @@ Usage
<patchName>
{
type freestreamPressure;
freestreamValue uniform 1e5;
}
\endverbatim
Note
This condition is designed to operate with a freestream velocity condition
This condition is designed to operate with a freestreamVelocity condition
See also
Foam::zeroGradientFvPatchField
Foam::mixedFvPatchField
Foam::freestreamFvPatchField
SourceFiles
@ -64,7 +66,7 @@ SourceFiles
#define freestreamPressureFvPatchScalarField_H
#include "fvPatchFields.H"
#include "zeroGradientFvPatchFields.H"
#include "mixedFvPatchFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -77,20 +79,13 @@ namespace Foam
class freestreamPressureFvPatchScalarField
:
public zeroGradientFvPatchScalarField
public mixedFvPatchScalarField
{
// Private data
//- Name of the velocity field
word UName_;
//- Name of the flux transporting the field
word phiName_;
//- Name of the density field used to normalise the mass flux
//- if necessary
word rhoName_;
public:
@ -162,6 +157,17 @@ public:
// Member functions
const scalarField& freestreamValue() const
{
return refValue();
}
scalarField& freestreamValue()
{
return refValue();
}
// Evaluation functions
//- Update the coefficients associated with the patch field

View File

@ -0,0 +1,136 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "freestreamVelocityFvPatchVectorField.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::freestreamVelocityFvPatchVectorField::freestreamVelocityFvPatchVectorField
(
const fvPatch& p,
const DimensionedField<vector, volMesh>& iF
)
:
mixedFvPatchVectorField(p, iF)
{}
Foam::freestreamVelocityFvPatchVectorField::freestreamVelocityFvPatchVectorField
(
const fvPatch& p,
const DimensionedField<vector, volMesh>& iF,
const dictionary& dict
)
:
mixedFvPatchVectorField(p, iF)
{
freestreamValue() = vectorField("freestreamValue", dict, p.size());
if (dict.found("value"))
{
fvPatchVectorField::operator=
(
vectorField("value", dict, p.size())
);
}
else
{
fvPatchVectorField::operator=(freestreamValue());
}
refGrad() = Zero;
valueFraction() = 1;
}
Foam::freestreamVelocityFvPatchVectorField::freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField& ptf,
const fvPatch& p,
const DimensionedField<vector, volMesh>& iF,
const fvPatchFieldMapper& mapper
)
:
mixedFvPatchVectorField(ptf, p, iF, mapper)
{}
Foam::freestreamVelocityFvPatchVectorField::freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField& wbppsf
)
:
mixedFvPatchVectorField(wbppsf)
{}
Foam::freestreamVelocityFvPatchVectorField::freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField& wbppsf,
const DimensionedField<vector, volMesh>& iF
)
:
mixedFvPatchVectorField(wbppsf, iF)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::freestreamVelocityFvPatchVectorField::updateCoeffs()
{
if (updated())
{
return;
}
const Field<vector>& Up = *this;
valueFraction() = 0.5 - 0.5*(Up & patch().nf())/mag(Up);
mixedFvPatchField<vector>::updateCoeffs();
}
void Foam::freestreamVelocityFvPatchVectorField::write(Ostream& os) const
{
fvPatchVectorField::write(os);
freestreamValue().writeEntry("freestreamValue", os);
writeEntry("value", os);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
makePatchTypeField
(
fvPatchVectorField,
freestreamVelocityFvPatchVectorField
);
}
// ************************************************************************* //

View File

@ -0,0 +1,184 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::freestreamVelocityFvPatchVectorField
Group
grpInletBoundaryConditions grpOutletBoundaryConditions
Description
This boundary condition provides a free-stream condition for velocity.
It is an inlet-outlet condition that uses the velocity orientation to
continuously blend between fixed value for normal inlet and zero gradient
for normal outlet flow.
Usage
\table
Property | Description | Required | Default value
freestreamValue | freestream velocity | yes |
\endtable
Example of the boundary condition specification:
\verbatim
<patchName>
{
type freestreamVelocity;
freestreamValue uniform (300 0 0);
}
\endverbatim
Note
This condition is designed to operate with the freestreamPressure condition
See also
Foam::mixedFvPatchField
Foam::freestreamFvPatchField
SourceFiles
freestreamVelocityFvPatchVectorField.C
\*---------------------------------------------------------------------------*/
#ifndef freestreamVelocityFvPatchVectorField_H
#define freestreamVelocityFvPatchVectorField_H
#include "fvPatchFields.H"
#include "mixedFvPatchFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class freestreamVelocityFvPatchVectorField Declaration
\*---------------------------------------------------------------------------*/
class freestreamVelocityFvPatchVectorField
:
public mixedFvPatchVectorField
{
public:
//- Runtime type information
TypeName("freestreamVelocity");
// Constructors
//- Construct from patch and internal field
freestreamVelocityFvPatchVectorField
(
const fvPatch&,
const DimensionedField<vector, volMesh>&
);
//- Construct from patch, internal field and dictionary
freestreamVelocityFvPatchVectorField
(
const fvPatch&,
const DimensionedField<vector, volMesh>&,
const dictionary&
);
//- Construct by mapping given freestreamVelocityFvPatchVectorField onto
// a new patch
freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField&,
const fvPatch&,
const DimensionedField<vector, volMesh>&,
const fvPatchFieldMapper&
);
//- Construct as copy
freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField&
);
//- Construct and return a clone
virtual tmp<fvPatchVectorField> clone() const
{
return tmp<fvPatchVectorField>
(
new freestreamVelocityFvPatchVectorField(*this)
);
}
//- Construct as copy setting internal field reference
freestreamVelocityFvPatchVectorField
(
const freestreamVelocityFvPatchVectorField&,
const DimensionedField<vector, volMesh>&
);
//- Construct and return a clone setting internal field reference
virtual tmp<fvPatchVectorField> clone
(
const DimensionedField<vector, volMesh>& iF
) const
{
return tmp<fvPatchVectorField>
(
new freestreamVelocityFvPatchVectorField(*this, iF)
);
}
// Member functions
const vectorField& freestreamValue() const
{
return refValue();
}
vectorField& freestreamValue()
{
return refValue();
}
// Evaluation functions
//- Update the coefficients associated with the patch field
virtual void updateCoeffs();
//- Write
virtual void write(Ostream&) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -75,7 +75,7 @@ swirlFlowRateInletVelocityFvPatchVectorField
dict.lookupOrDefault
(
"axis",
patch().size()
returnReduce(patch().size(), maxOp<label>())
? -gSum(patch().Sf())/gSum(patch().magSf())
: Zero
)
@ -145,48 +145,53 @@ void Foam::swirlFlowRateInletVelocityFvPatchVectorField::updateCoeffs()
{
return;
}
const scalar t = this->db().time().timeOutputValue();
const scalar flowRate = flowRate_->value(t);
const scalar rpm = rpm_->value(t);
const scalar totArea = gSum(patch().magSf());
const scalar avgU = -flowRate/totArea;
const vector axisHat = axis_/mag(axis_);
// Update angular velocity - convert [rpm] to [rad/s]
tmp<vectorField> tangentialVelocity
(
axisHat ^ (rpm*constant::mathematical::pi/30.0)*(patch().Cf() - origin_)
);
tmp<vectorField> n = patch().nf();
const surfaceScalarField& phi =
db().lookupObject<surfaceScalarField>(phiName_);
if (phi.dimensions() == dimVelocity*dimArea)
if (totArea > ROOTVSMALL && axis_ != vector(Zero))
{
// volumetric flow-rate
operator==(tangentialVelocity + n*avgU);
}
else if (phi.dimensions() == dimDensity*dimVelocity*dimArea)
{
const fvPatchField<scalar>& rhop =
patch().lookupPatchField<volScalarField, scalar>(rhoName_);
const scalar t = this->db().time().timeOutputValue();
const scalar flowRate = flowRate_->value(t);
const scalar rpm = rpm_->value(t);
// mass flow-rate
operator==(tangentialVelocity + n*avgU/rhop);
}
else
{
FatalErrorInFunction
<< "dimensions of " << phiName_ << " are incorrect" << nl
<< " on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< nl << exit(FatalError);
const scalar avgU = -flowRate/totArea;
const vector axisHat = axis_/mag(axis_);
// Update angular velocity - convert [rpm] to [rad/s]
tmp<vectorField> tangentialVelocity
(
axisHat
^(rpm*constant::mathematical::pi/30.0)
*(patch().Cf() - origin_)
);
tmp<vectorField> n = patch().nf();
const surfaceScalarField& phi =
db().lookupObject<surfaceScalarField>(phiName_);
if (phi.dimensions() == dimVelocity*dimArea)
{
// volumetric flow-rate
operator==(tangentialVelocity + n*avgU);
}
else if (phi.dimensions() == dimDensity*dimVelocity*dimArea)
{
const fvPatchField<scalar>& rhop =
patch().lookupPatchField<volScalarField, scalar>(rhoName_);
// mass flow-rate
operator==(tangentialVelocity + n*avgU/rhop);
}
else
{
FatalErrorInFunction
<< "dimensions of " << phiName_ << " are incorrect" << nl
<< " on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< nl << exit(FatalError);
}
}
fixedValueFvPatchField<vector>::updateCoeffs();

View File

@ -261,7 +261,7 @@ EulerDdtScheme<Type>::fvcDdt
new GeometricField<Type, fvPatchField, volMesh>
(
ddtIOobject,
rDeltaT.value()*
rDeltaT*
(
alpha()
*rho()

View File

@ -0,0 +1,230 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "cellLimitedGrad.H"
#include "gaussGrad.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type, class Limiter>
void Foam::fv::cellLimitedGrad<Type, Limiter>::limitGradient
(
const Field<scalar>& limiter,
Field<vector>& gIf
) const
{
gIf *= limiter;
}
template<class Type, class Limiter>
void Foam::fv::cellLimitedGrad<Type, Limiter>::limitGradient
(
const Field<vector>& limiter,
Field<tensor>& gIf
) const
{
forAll(gIf, celli)
{
gIf[celli] = tensor
(
cmptMultiply(limiter[celli], gIf[celli].x()),
cmptMultiply(limiter[celli], gIf[celli].y()),
cmptMultiply(limiter[celli], gIf[celli].z())
);
}
}
template<class Type, class Limiter>
Foam::tmp
<
Foam::GeometricField
<
typename Foam::outerProduct<Foam::vector, Type>::type,
Foam::fvPatchField,
Foam::volMesh
>
>
Foam::fv::cellLimitedGrad<Type, Limiter>::calcGrad
(
const GeometricField<Type, fvPatchField, volMesh>& vsf,
const word& name
) const
{
const fvMesh& mesh = vsf.mesh();
tmp
<
GeometricField
<typename outerProduct<vector, Type>::type, fvPatchField, volMesh>
> tGrad = basicGradScheme_().calcGrad(vsf, name);
if (k_ < SMALL)
{
return tGrad;
}
GeometricField
<
typename outerProduct<vector, Type>::type,
fvPatchField,
volMesh
>& g = tGrad.ref();
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
const volVectorField& C = mesh.C();
const surfaceVectorField& Cf = mesh.Cf();
Field<Type> maxVsf(vsf.primitiveField());
Field<Type> minVsf(vsf.primitiveField());
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
const Type& vsfOwn = vsf[own];
const Type& vsfNei = vsf[nei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
maxVsf[nei] = max(maxVsf[nei], vsfOwn);
minVsf[nei] = min(minVsf[nei], vsfOwn);
}
const typename GeometricField<Type, fvPatchField, volMesh>::Boundary& bsf =
vsf.boundaryField();
forAll(bsf, patchi)
{
const fvPatchField<Type>& psf = bsf[patchi];
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
if (psf.coupled())
{
const Field<Type> psfNei(psf.patchNeighbourField());
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
const Type& vsfNei = psfNei[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
else
{
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
const Type& vsfNei = psf[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
}
maxVsf -= vsf;
minVsf -= vsf;
if (k_ < 1.0)
{
const Field<Type> maxMinVsf((1.0/k_ - 1.0)*(maxVsf - minVsf));
maxVsf += maxMinVsf;
minVsf -= maxMinVsf;
}
// Create limiter initialized to 1
// Note: the limiter is not permitted to be > 1
Field<Type> limiter(vsf.primitiveField().size(), pTraits<Type>::one);
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
// owner side
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
(Cf[facei] - C[own]) & g[own]
);
// neighbour side
limitFace
(
limiter[nei],
maxVsf[nei],
minVsf[nei],
(Cf[facei] - C[nei]) & g[nei]
);
}
forAll(bsf, patchi)
{
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
const vectorField& pCf = Cf.boundaryField()[patchi];
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
((pCf[pFacei] - C[own]) & g[own])
);
}
}
if (fv::debug)
{
Info<< "gradient limiter for: " << vsf.name()
<< " max = " << gMax(limiter)
<< " min = " << gMin(limiter)
<< " average: " << gAverage(limiter) << endl;
}
limitGradient(limiter, g);
g.correctBoundaryConditions();
gaussGrad<Type>::correctBoundaryConditions(vsf, g);
return tGrad;
}
// ************************************************************************* //

View File

@ -44,14 +44,13 @@ SourceFiles
#define cellLimitedGrad_H
#include "gradScheme.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace fv
{
@ -59,10 +58,11 @@ namespace fv
Class cellLimitedGrad Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
template<class Type, class Limiter>
class cellLimitedGrad
:
public fv::gradScheme<Type>
public fv::gradScheme<Type>,
public Limiter
{
// Private Data
@ -74,6 +74,18 @@ class cellLimitedGrad
// Private Member Functions
void limitGradient
(
const Field<scalar>& limiter,
Field<vector>& gIf
) const;
void limitGradient
(
const Field<vector>& limiter,
Field<tensor>& gIf
) const;
//- Disallow default bitwise copy construct
cellLimitedGrad(const cellLimitedGrad&);
@ -93,6 +105,7 @@ public:
cellLimitedGrad(const fvMesh& mesh, Istream& schemeData)
:
gradScheme<Type>(mesh),
Limiter(schemeData),
basicGradScheme_(fv::gradScheme<Type>::New(mesh, schemeData)),
k_(readScalar(schemeData))
{
@ -110,13 +123,21 @@ public:
// Member Functions
static inline void limitFace
inline void limitFaceCmpt
(
scalar& limiter,
const scalar maxDelta,
const scalar minDelta,
const scalar extrapolate
) const;
inline void limitFace
(
Type& limiter,
const Type& maxDelta,
const Type& minDelta,
const Type& extrapolate
);
) const;
//- Return the gradient of the given field to the gradScheme::grad
// for optional caching
@ -134,73 +155,67 @@ public:
// * * * * * * * * * * * * Inline Member Function * * * * * * * * * * * * * //
template<>
inline void cellLimitedGrad<scalar>::limitFace
template<class Type, class Limiter>
inline void cellLimitedGrad<Type, Limiter>::limitFaceCmpt
(
scalar& limiter,
const scalar& maxDelta,
const scalar& minDelta,
const scalar& extrapolate
)
const scalar maxDelta,
const scalar minDelta,
const scalar extrapolate
) const
{
if (extrapolate > maxDelta + VSMALL)
scalar r = 1;
if (extrapolate > SMALL)
{
limiter = min(limiter, maxDelta/extrapolate);
r = maxDelta/extrapolate;
}
else if (extrapolate < minDelta - VSMALL)
else if (extrapolate < -SMALL)
{
limiter = min(limiter, minDelta/extrapolate);
r = minDelta/extrapolate;
}
else
{
return;
}
limiter = min(limiter, Limiter::limiter(r));
}
template<class Type>
inline void cellLimitedGrad<Type>::limitFace
template<class Type, class Limiter>
inline void cellLimitedGrad<Type, Limiter>::limitFace
(
Type& limiter,
const Type& maxDelta,
const Type& minDelta,
const Type& extrapolate
)
) const
{
for (direction cmpt=0; cmpt<Type::nComponents; cmpt++)
for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; ++cmpt)
{
cellLimitedGrad<scalar>::limitFace
limitFaceCmpt
(
limiter.component(cmpt),
maxDelta.component(cmpt),
minDelta.component(cmpt),
extrapolate.component(cmpt)
setComponent(limiter, cmpt),
component(maxDelta, cmpt),
component(minDelta, cmpt),
component(extrapolate, cmpt)
);
}
}
// * * * * * * * * Template Member Function Specialisations * * * * * * * * //
template<>
tmp<volVectorField> cellLimitedGrad<scalar>::calcGrad
(
const volScalarField& vsf,
const word& name
) const;
template<>
tmp<volTensorField> cellLimitedGrad<vector>::calcGrad
(
const volVectorField& vsf,
const word& name
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
#ifdef NoRepository
#include "cellLimitedGrad.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -24,335 +24,49 @@ License
\*---------------------------------------------------------------------------*/
#include "cellLimitedGrad.H"
#include "gaussGrad.H"
#include "fvMesh.H"
#include "volMesh.H"
#include "surfaceMesh.H"
#include "volFields.H"
#include "fixedValueFvPatchFields.H"
#include "minmodGradientLimiter.H"
#include "VenkatakrishnanGradientLimiter.H"
#include "cubicGradientLimiter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
makeFvGradScheme(cellLimitedGrad)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<>
Foam::tmp<Foam::volVectorField>
Foam::fv::cellLimitedGrad<Foam::scalar>::calcGrad
(
const volScalarField& vsf,
const word& name
) const
{
const fvMesh& mesh = vsf.mesh();
tmp<volVectorField> tGrad = basicGradScheme_().calcGrad(vsf, name);
if (k_ < SMALL)
{
return tGrad;
#define makeNamedFvLimitedGradTypeScheme(SS, Type, Limiter, Name) \
typedef Foam::fv::SS<Foam::Type, Foam::fv::gradientLimiters::Limiter> \
SS##Type##Limiter##_; \
\
defineTemplateTypeNameAndDebugWithName \
( \
SS##Type##Limiter##_, \
Name, \
0 \
); \
\
namespace Foam \
{ \
namespace fv \
{ \
gradScheme<Type>::addIstreamConstructorToTable \
< \
SS<Type, gradientLimiters::Limiter> \
> add##SS##Type##Limiter##IstreamConstructorToTable_; \
} \
}
volVectorField& g = tGrad.ref();
#define makeFvLimitedGradTypeScheme(SS, Type, Limiter) \
makeNamedFvLimitedGradTypeScheme(SS##Grad, Type, Limiter, #SS"<"#Limiter">")
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
#define makeFvLimitedGradScheme(SS, Limiter) \
\
makeFvLimitedGradTypeScheme(SS, scalar, Limiter) \
makeFvLimitedGradTypeScheme(SS, vector, Limiter)
const volVectorField& C = mesh.C();
const surfaceVectorField& Cf = mesh.Cf();
scalarField maxVsf(vsf.primitiveField());
scalarField minVsf(vsf.primitiveField());
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
scalar vsfOwn = vsf[own];
scalar vsfNei = vsf[nei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
maxVsf[nei] = max(maxVsf[nei], vsfOwn);
minVsf[nei] = min(minVsf[nei], vsfOwn);
}
const volScalarField::Boundary& bsf = vsf.boundaryField();
forAll(bsf, patchi)
{
const fvPatchScalarField& psf = bsf[patchi];
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
if (psf.coupled())
{
const scalarField psfNei(psf.patchNeighbourField());
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
scalar vsfNei = psfNei[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
else
{
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
scalar vsfNei = psf[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
}
maxVsf -= vsf;
minVsf -= vsf;
if (k_ < 1.0)
{
const scalarField maxMinVsf((1.0/k_ - 1.0)*(maxVsf - minVsf));
maxVsf += maxMinVsf;
minVsf -= maxMinVsf;
//maxVsf *= 1.0/k_;
//minVsf *= 1.0/k_;
}
// create limiter
scalarField limiter(vsf.primitiveField().size(), 1.0);
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
// owner side
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
(Cf[facei] - C[own]) & g[own]
);
// neighbour side
limitFace
(
limiter[nei],
maxVsf[nei],
minVsf[nei],
(Cf[facei] - C[nei]) & g[nei]
);
}
forAll(bsf, patchi)
{
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
const vectorField& pCf = Cf.boundaryField()[patchi];
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
(pCf[pFacei] - C[own]) & g[own]
);
}
}
if (fv::debug)
{
Info<< "gradient limiter for: " << vsf.name()
<< " max = " << gMax(limiter)
<< " min = " << gMin(limiter)
<< " average: " << gAverage(limiter) << endl;
}
g.primitiveFieldRef() *= limiter;
g.correctBoundaryConditions();
gaussGrad<scalar>::correctBoundaryConditions(vsf, g);
return tGrad;
}
template<>
Foam::tmp<Foam::volTensorField>
Foam::fv::cellLimitedGrad<Foam::vector>::calcGrad
(
const volVectorField& vsf,
const word& name
) const
{
const fvMesh& mesh = vsf.mesh();
tmp<volTensorField> tGrad = basicGradScheme_().calcGrad(vsf, name);
if (k_ < SMALL)
{
return tGrad;
}
volTensorField& g = tGrad.ref();
const labelUList& owner = mesh.owner();
const labelUList& neighbour = mesh.neighbour();
const volVectorField& C = mesh.C();
const surfaceVectorField& Cf = mesh.Cf();
vectorField maxVsf(vsf.primitiveField());
vectorField minVsf(vsf.primitiveField());
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
const vector& vsfOwn = vsf[own];
const vector& vsfNei = vsf[nei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
maxVsf[nei] = max(maxVsf[nei], vsfOwn);
minVsf[nei] = min(minVsf[nei], vsfOwn);
}
const volVectorField::Boundary& bsf = vsf.boundaryField();
forAll(bsf, patchi)
{
const fvPatchVectorField& psf = bsf[patchi];
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
if (psf.coupled())
{
const vectorField psfNei(psf.patchNeighbourField());
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
const vector& vsfNei = psfNei[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
else
{
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
const vector& vsfNei = psf[pFacei];
maxVsf[own] = max(maxVsf[own], vsfNei);
minVsf[own] = min(minVsf[own], vsfNei);
}
}
}
maxVsf -= vsf;
minVsf -= vsf;
if (k_ < 1.0)
{
const vectorField maxMinVsf((1.0/k_ - 1.0)*(maxVsf - minVsf));
maxVsf += maxMinVsf;
minVsf -= maxMinVsf;
//maxVsf *= 1.0/k_;
//minVsf *= 1.0/k_;
}
// create limiter
vectorField limiter(vsf.primitiveField().size(), vector::one);
forAll(owner, facei)
{
label own = owner[facei];
label nei = neighbour[facei];
// owner side
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
(Cf[facei] - C[own]) & g[own]
);
// neighbour side
limitFace
(
limiter[nei],
maxVsf[nei],
minVsf[nei],
(Cf[facei] - C[nei]) & g[nei]
);
}
forAll(bsf, patchi)
{
const labelUList& pOwner = mesh.boundary()[patchi].faceCells();
const vectorField& pCf = Cf.boundaryField()[patchi];
forAll(pOwner, pFacei)
{
label own = pOwner[pFacei];
limitFace
(
limiter[own],
maxVsf[own],
minVsf[own],
((pCf[pFacei] - C[own]) & g[own])
);
}
}
if (fv::debug)
{
Info<< "gradient limiter for: " << vsf.name()
<< " max = " << gMax(limiter)
<< " min = " << gMin(limiter)
<< " average: " << gAverage(limiter) << endl;
}
tensorField& gIf = g.primitiveFieldRef();
forAll(gIf, celli)
{
gIf[celli] = tensor
(
cmptMultiply(limiter[celli], gIf[celli].x()),
cmptMultiply(limiter[celli], gIf[celli].y()),
cmptMultiply(limiter[celli], gIf[celli].z())
);
}
g.correctBoundaryConditions();
gaussGrad<vector>::correctBoundaryConditions(vsf, g);
return tGrad;
}
// Default limiter in minmod specified without the limiter name
// for backward compatibility
makeNamedFvLimitedGradTypeScheme(cellLimitedGrad, scalar, minmod, "cellLimited")
makeNamedFvLimitedGradTypeScheme(cellLimitedGrad, vector, minmod, "cellLimited")
makeFvLimitedGradScheme(cellLimited, Venkatakrishnan)
makeFvLimitedGradScheme(cellLimited, cubic)
// ************************************************************************* //

View File

@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::fv::gradientLimiters::Venkatakrishnan
Description
Venkatakrishnan gradient limiter
to be used with the Foam::fv::cellLimitedGrad limited gradient.
Reference:
\verbatim
Venkatakrishnan, V. (1993).
On the accuracy of limiters and convergence to steady state solutions.
In 31st Aerospace Sciences Meeting (p. 880).
\endverbatim
Example:
\verbatim
gradSchemes
{
default Gauss linear;
limited cellLimited<Venkatakrishnan> Gauss linear 1;
}
\endverbatim
Note: this limiter formally allows the limiter function to slightly exceed 1
which is generally not a good idea and can cause unboundedness. To avoid
this problem the limiter function is clipped to 1 which is likely to be
better behaved but is then not differentiable and so no longer conforms to
the basic principles of this kind of limiter function. All these issues are
resolved in a consistent and differentiable manner by the
Foam::fv::gradientLimiters::cubic limiter which is recommended in
preference to the Foam::fv::gradientLimiters::Venkatakrishnan limiter.
See also
Foam::fv::cellLimitedGrad
Foam::fv::gradientLimiters::cubic
\*---------------------------------------------------------------------------*/
#ifndef VenkatakrishnanGradientLimiter_H
#define VenkatakrishnanGradientLimiter_H
#include "Istream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
namespace gradientLimiters
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
class Venkatakrishnan
{
public:
// Constructors
Venkatakrishnan(Istream&)
{}
// Member Functions
inline scalar limiter(const scalar r) const
{
return (sqr(r) + 2*r)/(sqr(r) + r + 2);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace gradientLimiters
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,146 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::fv::gradientLimiters::minmod
Description
Cubic gradient limiter
to be used with the Foam::fv::cellLimitedGrad limited gradient. This
limiter function is similar to Foam::fv::gradientLimiters::Venkatakrishnan
but is a fit to obey the value and gradient constraints and avoids the
problem of the limiter exceeding 1 present in the Venkatakrishnan function.
The transition point at which the limiter function reaches 1 is an input
parameter and should be set to a value between 1 and 2 although values
larger than 2 are physical but likely to significantly reduce the accuracy
of the scheme.
Reference:
\verbatim
Michalak, K., & Ollivier-Gooch, C. (2008).
Limiters for unstructured higher-order accurate solutions
of the Euler equations.
In 46th AIAA Aerospace Sciences Meeting and Exhibit (p. 776).
\endverbatim
Example:
\verbatim
gradSchemes
{
default Gauss linear;
limited cellLimited<cubic> 1.5 Gauss linear 1;
}
\endverbatim
See also
Foam::fv::cellLimitedGrad
Foam::fv::gradientLimiters::Venkatakrishnan
\*---------------------------------------------------------------------------*/
#ifndef cubicGradientLimiter_H
#define cubicGradientLimiter_H
#include "Istream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
namespace gradientLimiters
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
class cubic
{
// Private Data
//- Limiter transition point at which the limiter function -> 1
// Must be > 1
const scalar rt_;
//- Coefficient of the r^3 term (evaluated from rt)
const scalar a_;
// - Coefficient of the r^2 term (evaluated from rt)
const scalar b_;
public:
// Constructors
cubic(Istream& schemeData)
:
rt_(readScalar(schemeData)),
a_(2.0/sqr(rt_) - 2.0/pow3(rt_)),
b_(-(3.0/2.0)*a_*rt_)
{
if (rt_ < 1)
{
FatalIOErrorInFunction
(
schemeData
) << "coefficient = " << rt_
<< " should be > 1"
<< exit(FatalIOError);
}
}
// Member Functions
inline scalar limiter(const scalar r) const
{
if (r < rt_)
{
return ((a_*r + b_)*r + 1)*r;
}
else
{
return 1;
}
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace gradientLimiters
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,99 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::fv::gradientLimiters::minmod
Description
Minmod gradient limiter
This is the default gradient limiter which clips the gradient to remove cell
to face extrapolation unboundedness. It corresponds to the original
cellLimitedGrad implementation before the addition of run-time select-able
limiter functions.
Example:
\verbatim
gradSchemes
{
default Gauss linear;
limited cellLimited Gauss linear 1;
}
\endverbatim
See also
Foam::fv::cellLimitedGrad
\*---------------------------------------------------------------------------*/
#ifndef minmodGradientLimiter_H
#define minmodGradientLimiter_H
#include "Istream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace fv
{
namespace gradientLimiters
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
class minmod
{
public:
// Constructors
minmod(Istream&)
{}
// Member Functions
inline scalar limiter(const scalar r) const
{
return min(r, 1);
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace gradientLimiters
} // End namespace fv
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -61,7 +61,8 @@ Foam::functionObjects::turbulenceFields::compressibleFieldNames_
{ compressibleField::cfAlphaEff, "alphaEff" },
{ compressibleField::cfR, "R" },
{ compressibleField::cfDevRhoReff, "devRhoReff" },
{ compressibleField::cfL, "L" }
{ compressibleField::cfL, "L" },
{ compressibleField::cfI, "I" }
};
@ -80,6 +81,7 @@ Foam::functionObjects::turbulenceFields::incompressibleFieldNames_
{ incompressibleField::ifR, "R" },
{ incompressibleField::ifDevReff, "devReff" },
{ incompressibleField::ifL, "L" },
{ incompressibleField::ifI, "I" }
};
@ -236,6 +238,11 @@ bool Foam::functionObjects::turbulenceFields::execute()
processField<scalar>(f, L(model));
break;
}
case cfI:
{
processField<scalar>(f, I(model));
break;
}
default:
{
FatalErrorInFunction
@ -298,6 +305,11 @@ bool Foam::functionObjects::turbulenceFields::execute()
processField<scalar>(f, L(model));
break;
}
case ifI:
{
processField<scalar>(f, I(model));
break;
}
default:
{
FatalErrorInFunction

View File

@ -76,6 +76,7 @@ Usage
devReff | Deviatoric part of the effective Reynolds stress
devRhoReff | Divergence of the Reynolds stress
L | turbulence length scale
I | turbulence intensity
\endplaintable
See also
@ -125,7 +126,8 @@ public:
cfAlphaEff,
cfR,
cfDevRhoReff,
cfL
cfL,
cfI
};
static const Enum<compressibleField> compressibleFieldNames_;
@ -139,7 +141,8 @@ public:
ifNuEff,
ifR,
ifDevReff,
ifL
ifL,
ifI
};
static const Enum<incompressibleField> incompressibleFieldNames_;
@ -179,6 +182,10 @@ protected:
template<class Model>
tmp<volScalarField> L(const Model& model) const;
//- Return I calculated from k and U
template<class Model>
tmp<volScalarField> I(const Model& model) const;
private:

View File

@ -85,19 +85,16 @@ Foam::functionObjects::turbulenceFields::omega
const volScalarField k(model.k());
const volScalarField epsilon(model.epsilon());
return tmp<volScalarField>
return tmp<volScalarField>::New
(
new volScalarField
IOobject
(
IOobject
(
"omega.tmp",
k.mesh().time().timeName(),
k.mesh()
),
epsilon/(Cmu*k),
epsilon.boundaryField().types()
)
"omega.tmp",
k.mesh().time().timeName(),
k.mesh()
),
epsilon/(Cmu*k),
epsilon.boundaryField().types()
);
}
@ -109,9 +106,10 @@ Foam::functionObjects::turbulenceFields::nuTilda
const Model& model
) const
{
return tmp<volScalarField>
return tmp<volScalarField>::New
(
new volScalarField("nuTilda.tmp", model.k()/omega(model))
"nuTilda.tmp",
model.k()/omega(model)
);
}
@ -130,15 +128,30 @@ Foam::functionObjects::turbulenceFields::L
const volScalarField epsilon(model.epsilon());
const dimensionedScalar eps0("eps0", epsilon.dimensions(), SMALL);
return tmp<volScalarField>
return tmp<volScalarField>::New
(
new volScalarField
(
"L.tmp",
pow(Cmu, 0.75)*pow(k, 1.5)/(epsilon + eps0)
)
"L.tmp",
pow(Cmu, 0.75)*pow(k, 1.5)/(epsilon + eps0)
);
}
template<class Model>
Foam::tmp<Foam::volScalarField>
Foam::functionObjects::turbulenceFields::I
(
const Model& model
) const
{
// Assume k is available
const volScalarField uPrime(sqrt((2.0/3.0)*model.k()));
const dimensionedScalar U0("U0", dimVelocity, SMALL);
return tmp<volScalarField>::New
(
"I.tmp",
uPrime/max(max(uPrime, mag(model.U())), U0)
);
}
// ************************************************************************* //

View File

@ -353,7 +353,7 @@ Foam::functionObjects::forces::devRhoReff() const
const dictionary& transportProperties =
lookupObject<dictionary>("transportProperties");
dimensionedScalar nu(transportProperties.lookup("nu"));
dimensionedScalar nu("nu", dimViscosity, transportProperties);
const volVectorField& U = lookupObject<volVectorField>(UName_);

View File

@ -108,6 +108,7 @@ bool Foam::functionObjects::vtkWrite::read(const dictionary& dict)
//
dict.readIfPresent("directory", dirName_);
decompose_ = dict.lookupOrDefault("decompose", false);
writeIds_ = dict.lookupOrDefault("writeIds", false);
@ -185,7 +186,7 @@ bool Foam::functionObjects::vtkWrite::write()
(
mesh_,
writeOpts_,
true // decompose
decompose_
);
// Write mesh

View File

@ -44,6 +44,7 @@ Description
writeInterval 1;
format binary;
legacy false;
decompose false;
...
fields (U p);
}
@ -51,14 +52,15 @@ Description
Usage
\table
Property | Description | Required | Default value
type | Type name: vtkWrite | yes |
fields | Fields to output | yes |
writeControl | Output control | recommended | timeStep
directory | The output directory name | no | "VTK"
format | ASCII or binary format | no | binary
legacy | Legacy VTK output | no | false
writeIds | Write cell ids as field | no | true
Property | Description | Required | Default
type | Type name: vtkWrite | yes |
fields | Fields to output | yes |
writeControl | Output control | recommended | timeStep
directory | The output directory name | no | "VTK"
format | ASCII or binary format | no | binary
legacy | Legacy VTK output | no | false
decompose | decompose polyhedra | no | false
writeIds | Write cell ids as field | no | true
\endtable
See also
@ -106,6 +108,9 @@ class vtkWrite
//- Output directory name
fileName dirName_;
//- Decompose polyhedra
bool decompose_;
//- Write cell ids field
bool writeIds_;
@ -119,7 +124,11 @@ class vtkWrite
//- Write selected fields for GeoField type.
template<class GeoField>
label writeFields(vtk::internalWriter& writer, bool verbose=true) const;
label writeFields
(
vtk::internalWriter& writer,
bool verbose=true
) const;
//- Write selected fields for GeoField type.
@ -131,10 +140,10 @@ class vtkWrite
) const;
//- Disallow default bitwise copy construct
//- No copy construct
vtkWrite(const vtkWrite&) = delete;
//- Disallow default bitwise assignment
//- No copy assignment
void operator=(const vtkWrite&) = delete;
@ -150,7 +159,7 @@ public:
vtkWrite
(
const word& name,
const Time& t,
const Time& runTime,
const dictionary& dict
);

View File

@ -57,34 +57,6 @@ registerInfoSwitch
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::particle::stationaryTetGeometry
(
vector& centre,
vector& base,
vector& vertex1,
vector& vertex2
) const
{
const triFace triIs(currentTetIndices().faceTriIs(mesh_));
const vectorField& ccs = mesh_.cellCentres();
const pointField& pts = mesh_.points();
centre = ccs[celli_];
base = pts[triIs[0]];
vertex1 = pts[triIs[1]];
vertex2 = pts[triIs[2]];
}
Foam::barycentricTensor Foam::particle::stationaryTetTransform() const
{
vector centre, base, vertex1, vertex2;
stationaryTetGeometry(centre, base, vertex1, vertex2);
return barycentricTensor(centre, base, vertex1, vertex2);
}
void Foam::particle::stationaryTetReverseTransform
(
vector& centre,
@ -114,61 +86,6 @@ void Foam::particle::stationaryTetReverseTransform
}
void Foam::particle::movingTetGeometry
(
const scalar fraction,
Pair<vector>& centre,
Pair<vector>& base,
Pair<vector>& vertex1,
Pair<vector>& vertex2
) const
{
const triFace triIs(currentTetIndices().faceTriIs(mesh_));
const pointField& ptsOld = mesh_.oldPoints();
const pointField& ptsNew = mesh_.points();
// !!! <-- We would be better off using mesh_.cellCentres() here. However,
// we need to put a mesh_.oldCellCentres() method in for this to work. The
// values obtained from the mesh and those obtained from the cell do not
// necessarily match. See mantis #1993.
const vector ccOld = mesh_.cells()[celli_].centre(ptsOld, mesh_.faces());
const vector ccNew = mesh_.cells()[celli_].centre(ptsNew, mesh_.faces());
// Old and new points and cell centres are not sub-cycled. If we are sub-
// cycling, then we have to account for the timestep change here by
// modifying the fractions that we take of the old and new geometry.
const Pair<scalar> s = stepFractionSpan();
const scalar f0 = s[0] + stepFraction_*s[1], f1 = fraction*s[1];
centre[0] = ccOld + f0*(ccNew - ccOld);
base[0] = ptsOld[triIs[0]] + f0*(ptsNew[triIs[0]] - ptsOld[triIs[0]]);
vertex1[0] = ptsOld[triIs[1]] + f0*(ptsNew[triIs[1]] - ptsOld[triIs[1]]);
vertex2[0] = ptsOld[triIs[2]] + f0*(ptsNew[triIs[2]] - ptsOld[triIs[2]]);
centre[1] = f1*(ccNew - ccOld);
base[1] = f1*(ptsNew[triIs[0]] - ptsOld[triIs[0]]);
vertex1[1] = f1*(ptsNew[triIs[1]] - ptsOld[triIs[1]]);
vertex2[1] = f1*(ptsNew[triIs[2]] - ptsOld[triIs[2]]);
}
Foam::Pair<Foam::barycentricTensor> Foam::particle::movingTetTransform
(
const scalar fraction
) const
{
Pair<vector> centre, base, vertex1, vertex2;
movingTetGeometry(fraction, centre, base, vertex1, vertex2);
return
Pair<barycentricTensor>
(
barycentricTensor(centre[0], base[0], vertex1[0], vertex2[0]),
barycentricTensor(centre[1], base[1], vertex1[1], vertex2[1])
);
}
void Foam::particle::movingTetReverseTransform
(
const scalar fraction,
@ -1013,47 +930,6 @@ Foam::vector Foam::particle::deviationFromMeshCentre() const
}
void Foam::particle::patchData(vector& n, vector& U) const
{
if (!onBoundaryFace())
{
FatalErrorInFunction
<< "Patch data was requested for a particle that isn't on a patch"
<< exit(FatalError);
}
if (mesh_.moving())
{
Pair<vector> centre, base, vertex1, vertex2;
movingTetGeometry(1, centre, base, vertex1, vertex2);
n = triPointRef(base[0], vertex1[0], vertex2[0]).normal();
n /= mag(n);
// Interpolate the motion of the three face vertices to the current
// coordinates
U =
coordinates_.b()*base[1]
+ coordinates_.c()*vertex1[1]
+ coordinates_.d()*vertex2[1];
// The movingTetGeometry method gives the motion as a displacement
// across the time-step, so we divide by the time-step to get velocity
U /= mesh_.time().deltaTValue();
}
else
{
vector centre, base, vertex1, vertex2;
stationaryTetGeometry(centre, base, vertex1, vertex2);
n = triPointRef(base, vertex1, vertex2).normal();
n /= mag(n);
U = Zero;
}
}
void Foam::particle::transformProperties(const tensor&)
{}

View File

@ -180,7 +180,7 @@ private:
// Tetrahedra functions
//- Get the vertices of the current tet
void stationaryTetGeometry
inline void stationaryTetGeometry
(
vector& centre,
vector& base,
@ -193,7 +193,7 @@ private:
// Cartesian position in the global coordinate system. The
// conversion is x = A & y, where x is the Cartesian position, y is
// the barycentric position and A is the transformation tensor.
barycentricTensor stationaryTetTransform() const;
inline barycentricTensor stationaryTetTransform() const;
//- Get the reverse transform associated with the current tet. The
// conversion is detA*y = (x - centre) & T. The variables x, y and
@ -212,7 +212,7 @@ private:
//- Get the vertices of the current moving tet. Two values are
// returned for each vertex. The first is a constant, and the
// second is a linear coefficient of the track fraction.
void movingTetGeometry
inline void movingTetGeometry
(
const scalar endStepFraction,
Pair<vector>& centre,
@ -225,7 +225,7 @@ private:
// This is of the same form as for the static case. As with the
// moving geometry, a linear function of the tracking fraction is
// returned for each component.
Pair<barycentricTensor> movingTetTransform
inline Pair<barycentricTensor> movingTetTransform
(
const scalar endStepFraction
) const;
@ -625,7 +625,7 @@ public:
// Patch data
//- Get the normal and velocity of the current patch location
void patchData(vector& n, vector& U) const;
inline void patchData(vector& n, vector& U) const;
// Transformations

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -26,6 +26,91 @@ License
#include "polyMesh.H"
#include "Time.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::particle::stationaryTetGeometry
(
vector& centre,
vector& base,
vector& vertex1,
vector& vertex2
) const
{
const triFace triIs(currentTetIndices().faceTriIs(mesh_));
const vectorField& ccs = mesh_.cellCentres();
const pointField& pts = mesh_.points();
centre = ccs[celli_];
base = pts[triIs[0]];
vertex1 = pts[triIs[1]];
vertex2 = pts[triIs[2]];
}
inline Foam::barycentricTensor Foam::particle::stationaryTetTransform() const
{
vector centre, base, vertex1, vertex2;
stationaryTetGeometry(centre, base, vertex1, vertex2);
return barycentricTensor(centre, base, vertex1, vertex2);
}
inline void Foam::particle::movingTetGeometry
(
const scalar fraction,
Pair<vector>& centre,
Pair<vector>& base,
Pair<vector>& vertex1,
Pair<vector>& vertex2
) const
{
const triFace triIs(currentTetIndices().faceTriIs(mesh_));
const pointField& ptsOld = mesh_.oldPoints();
const pointField& ptsNew = mesh_.points();
// !!! <-- We would be better off using mesh_.cellCentres() here. However,
// we need to put a mesh_.oldCellCentres() method in for this to work. The
// values obtained from the mesh and those obtained from the cell do not
// necessarily match. See mantis #1993.
const vector ccOld = mesh_.cells()[celli_].centre(ptsOld, mesh_.faces());
const vector ccNew = mesh_.cells()[celli_].centre(ptsNew, mesh_.faces());
// Old and new points and cell centres are not sub-cycled. If we are sub-
// cycling, then we have to account for the timestep change here by
// modifying the fractions that we take of the old and new geometry.
const Pair<scalar> s = stepFractionSpan();
const scalar f0 = s[0] + stepFraction_*s[1], f1 = fraction*s[1];
centre[0] = ccOld + f0*(ccNew - ccOld);
base[0] = ptsOld[triIs[0]] + f0*(ptsNew[triIs[0]] - ptsOld[triIs[0]]);
vertex1[0] = ptsOld[triIs[1]] + f0*(ptsNew[triIs[1]] - ptsOld[triIs[1]]);
vertex2[0] = ptsOld[triIs[2]] + f0*(ptsNew[triIs[2]] - ptsOld[triIs[2]]);
centre[1] = f1*(ccNew - ccOld);
base[1] = f1*(ptsNew[triIs[0]] - ptsOld[triIs[0]]);
vertex1[1] = f1*(ptsNew[triIs[1]] - ptsOld[triIs[1]]);
vertex2[1] = f1*(ptsNew[triIs[2]] - ptsOld[triIs[2]]);
}
inline Foam::Pair<Foam::barycentricTensor> Foam::particle::movingTetTransform
(
const scalar fraction
) const
{
Pair<vector> centre, base, vertex1, vertex2;
movingTetGeometry(fraction, centre, base, vertex1, vertex2);
return
Pair<barycentricTensor>
(
barycentricTensor(centre[0], base[0], vertex1[0], vertex2[0]),
barycentricTensor(centre[1], base[1], vertex1[1], vertex2[1])
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::label Foam::particle::getNewParticleID() const
@ -231,4 +316,45 @@ inline Foam::vector Foam::particle::position() const
}
void Foam::particle::patchData(vector& n, vector& U) const
{
if (!onBoundaryFace())
{
FatalErrorInFunction
<< "Patch data was requested for a particle that isn't on a patch"
<< exit(FatalError);
}
if (mesh_.moving())
{
Pair<vector> centre, base, vertex1, vertex2;
movingTetGeometry(1, centre, base, vertex1, vertex2);
n = triPointRef(base[0], vertex1[0], vertex2[0]).normal();
n /= mag(n);
// Interpolate the motion of the three face vertices to the current
// coordinates
U =
coordinates_.b()*base[1]
+ coordinates_.c()*vertex1[1]
+ coordinates_.d()*vertex2[1];
// The movingTetGeometry method gives the motion as a displacement
// across the time-step, so we divide by the time-step to get velocity
U /= mesh_.time().deltaTValue();
}
else
{
vector centre, base, vertex1, vertex2;
stationaryTetGeometry(centre, base, vertex1, vertex2);
n = triPointRef(base, vertex1, vertex2).normal();
n /= mag(n);
U = Zero;
}
}
// ************************************************************************* //

View File

@ -156,6 +156,8 @@ void Foam::particle::hitFace
}
else if (onBoundaryFace())
{
changeToMasterPatch();
if (!p.hitPatch(cloud, ttd))
{
const polyPatch& patch = mesh_.boundaryMesh()[p.patch()];
@ -212,11 +214,6 @@ void Foam::particle::trackToAndHitFace
{
trackToFace(direction, fraction);
if (onBoundaryFace())
{
changeToMasterPatch();
}
hitFace(direction, cloud, td);
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -34,6 +34,7 @@ License
#include "ParticleErosion.H"
#include "ParticleTracks.H"
#include "ParticleTrap.H"
#include "PatchCollisionDensity.H"
#include "PatchPostProcessing.H"
#include "VoidFraction.H"
@ -48,6 +49,7 @@ License
makeCloudFunctionObjectType(ParticleErosion, CloudType); \
makeCloudFunctionObjectType(ParticleTracks, CloudType); \
makeCloudFunctionObjectType(ParticleTrap, CloudType); \
makeCloudFunctionObjectType(PatchCollisionDensity, CloudType); \
makeCloudFunctionObjectType(PatchPostProcessing, CloudType); \
makeCloudFunctionObjectType(VoidFraction, CloudType);

View File

@ -0,0 +1,168 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "PatchCollisionDensity.H"
#include "Pstream.H"
#include "stringListOps.H"
#include "ListOps.H"
#include "ListListOps.H"
// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
template<class CloudType>
void Foam::PatchCollisionDensity<CloudType>::write()
{
const scalarField z(this->owner().mesh().nCells(), 0);
volScalarField
(
IOobject
(
this->owner().name() + ":collisionDensity",
this->owner().mesh().time().timeName(),
this->owner().mesh()
),
this->owner().mesh(),
dimless/dimArea,
z,
collisionDensity_
)
.write();
volScalarField
(
IOobject
(
this->owner().name() + ":collisionDensityRate",
this->owner().mesh().time().timeName(),
this->owner().mesh()
),
this->owner().mesh(),
dimless/dimArea/dimTime,
z,
(collisionDensity_ - collisionDensity0_)
/(this->owner().mesh().time().value() - time0_)
)
.write();
collisionDensity0_ == collisionDensity_;
time0_ = this->owner().mesh().time().value();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class CloudType>
Foam::PatchCollisionDensity<CloudType>::PatchCollisionDensity
(
const dictionary& dict,
CloudType& owner,
const word& modelName
)
:
CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
minSpeed_(dict.lookupOrDefault<scalar>("minSpeed", -1)),
collisionDensity_
(
this->owner().mesh().boundary(),
volScalarField::Internal::null(),
calculatedFvPatchField<scalar>::typeName
),
collisionDensity0_
(
this->owner().mesh().boundary(),
volScalarField::Internal::null(),
calculatedFvPatchField<scalar>::typeName
),
time0_(this->owner().mesh().time().value())
{
collisionDensity_ == 0;
collisionDensity0_ == 0;
IOobject io
(
this->owner().name() + ":collisionDensity",
this->owner().mesh().time().timeName(),
this->owner().mesh(),
IOobject::MUST_READ,
IOobject::NO_WRITE
);
if (io.typeHeaderOk<volScalarField>())
{
const volScalarField collisionDensity(io, this->owner().mesh());
collisionDensity_ == collisionDensity.boundaryField();
collisionDensity0_ == collisionDensity.boundaryField();
}
}
template<class CloudType>
Foam::PatchCollisionDensity<CloudType>::PatchCollisionDensity
(
const PatchCollisionDensity<CloudType>& ppm
)
:
CloudFunctionObject<CloudType>(ppm),
minSpeed_(ppm.minSpeed_),
collisionDensity_(ppm.collisionDensity_),
collisionDensity0_(ppm.collisionDensity0_),
time0_(ppm.time0_)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class CloudType>
Foam::PatchCollisionDensity<CloudType>::~PatchCollisionDensity()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class CloudType>
void Foam::PatchCollisionDensity<CloudType>::postPatch
(
const parcelType& p,
const polyPatch& pp,
bool&
)
{
const label patchi = pp.index();
const label patchFacei = p.face() - pp.start();
vector nw, Up;
this->owner().patchData(p, pp, nw, Up);
const scalar speed = (p.U() - Up) & nw;
if (speed > minSpeed_)
{
collisionDensity_[patchi][patchFacei] +=
1/this->owner().mesh().magSf().boundaryField()[patchi][patchFacei];
}
}
// ************************************************************************* //

View File

@ -0,0 +1,152 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 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 <http://www.gnu.org/licenses/>.
Class
Foam::PatchCollisionDensity
Description
Function object which generates fields of the number and rate of collisions
per unit area on all patches. Can optionally take a minimum speed below
which a collision is not counted.
Example usage:
\verbatim
patchCollisionDensity1
{
type patchCollisionDensity;
minSpeed 1e-3;
}
\endverbatim
SourceFiles
PatchCollisionDensity.C
\*---------------------------------------------------------------------------*/
#ifndef PatchCollisionDensity_H
#define PatchCollisionDensity_H
#include "CloudFunctionObject.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class PatchCollisionDensity Declaration
\*---------------------------------------------------------------------------*/
template<class CloudType>
class PatchCollisionDensity
:
public CloudFunctionObject<CloudType>
{
// Private data
typedef typename CloudType::particleType parcelType;
//- The threshold for a collision
const scalar minSpeed_;
//- The field of the number of collisions per unit area
volScalarField::Boundary collisionDensity_;
//- The field of the number of collisions per unit area at the last
// output
volScalarField::Boundary collisionDensity0_;
//- The time at the last output
scalar time0_;
protected:
// Protected Member Functions
//- Write post-processing info
void write();
public:
//- Runtime type information
TypeName("patchCollisionDensity");
// Constructors
//- Construct from dictionary
PatchCollisionDensity
(
const dictionary& dict,
CloudType& owner,
const word& modelName
);
//- Construct copy
PatchCollisionDensity(const PatchCollisionDensity<CloudType>& ppm);
//- Construct and return a clone
virtual autoPtr<CloudFunctionObject<CloudType>> clone() const
{
return autoPtr<CloudFunctionObject<CloudType>>
(
new PatchCollisionDensity<CloudType>(*this)
);
}
//- Destructor
virtual ~PatchCollisionDensity();
// Member Functions
// Evaluation
//- Post-patch hook
virtual void postPatch
(
const parcelType& p,
const polyPatch& pp,
bool& keepParticle
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "PatchCollisionDensity.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -250,7 +250,7 @@ void Foam::lumpedPointDisplacementPointPatchVectorField::updateCoeffs()
if (Pstream::master())
{
movement().writeData(forces, moments);
movement().writeData(forces, moments, &(db().time()));
// Signal external source to execute
movement().coupler().useSlave();

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -48,29 +48,65 @@ Foam::lumpedPointMovement::formatNames
};
const Foam::Enum
<
Foam::lumpedPointMovement::scalingType
>
Foam::lumpedPointMovement::scalingNames
{
{ scalingType::LENGTH, "plain" },
{ scalingType::FORCE, "force" },
{ scalingType::MOMENT, "moment" }
};
const Foam::word
Foam::lumpedPointMovement::dictionaryName("lumpedPointMovement");
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
//! \cond fileScope
//- Space-separated vector value (ASCII)
static inline Ostream& putPlain(Ostream& os, const vector& val)
{
os << val.x() << ' ' << val.y() << ' ' << val.z();
return os;
}
//! \cond fileScope
//- Space-separated vector value (ASCII)
static inline Ostream& putTime(Ostream& os, const Time& t)
{
os <<"Time index=" << t.timeIndex()
<< " value=" << t.timeOutputValue();
return os;
}
//! \cond fileScope
//- Write list content with size, bracket, content, bracket one-per-line.
// This makes for consistent for parsing, regardless of the list length.
template <class T>
static void writeList(Ostream& os, const string& header, const UList<T>& lst)
static void writeList(Ostream& os, const string& header, const UList<T>& list)
{
const label len = list.size();
// Header string
os << header.c_str() << nl;
// Write size and start delimiter
os << lst.size() << nl
<< token::BEGIN_LIST << nl;
os << len << nl << token::BEGIN_LIST << nl;
// Write contents
forAll(lst, i)
for (label i=0; i < len; ++i)
{
os << lst[i] << nl;
os << list[i] << nl;
}
// Write end delimiter
@ -165,8 +201,11 @@ Foam::lumpedPointMovement::lumpedPointMovement()
coupler_(),
inputName_("positions.in"),
outputName_("forces.out"),
logName_("movement.log"),
inputFormat_(lumpedPointState::inputFormatType::DICTIONARY),
outputFormat_(outputFormatType::DICTIONARY),
scaleInput_(-1.0),
scaleOutput_(-1.0),
state0_(),
state_(),
thresholdPtr_(0),
@ -198,6 +237,11 @@ Foam::lumpedPointMovement::lumpedPointMovement
autoCentre_(true),
forcesDict_(),
coupler_(),
inputName_("positions.in"),
outputName_("forces.out"),
logName_("movement.log"),
scaleInput_(-1.0),
scaleOutput_(-1.0),
state0_(),
state_(),
thresholdPtr_(0),
@ -262,6 +306,7 @@ void Foam::lumpedPointMovement::readDict(const dictionary& dict)
commDict.lookup("inputName") >> inputName_;
commDict.lookup("outputName") >> outputName_;
commDict.readIfPresent("logName", logName_);
inputFormat_ = lumpedPointState::formatNames.lookup
(
@ -274,6 +319,47 @@ void Foam::lumpedPointMovement::readDict(const dictionary& dict)
"outputFormat",
commDict
);
scaleInput_ = -1;
scaleOutput_ = -1;
const dictionary* scaleDict = nullptr;
if ((scaleDict = commDict.subDictPtr("scaleInput")))
{
for (int i=0; i < scaleInput_.size(); ++i)
{
const word& key = scalingNames[scalingType(i)];
if
(
scaleDict->readIfPresent(key, scaleInput_[i])
&& scaleInput_[i] > 0
)
{
Info<<"Using input " << key << " multiplier: "
<< scaleInput_[i] << nl;
}
}
}
if ((scaleDict = commDict.subDictPtr("scaleOutput")))
{
for (int i=0; i < scaleOutput_.size(); ++i)
{
const word& key = scalingNames[scalingType(i)];
if
(
scaleDict->readIfPresent(key, scaleOutput_[i])
&& scaleOutput_[i] > 0
)
{
Info<<"Using output " << key << " multiplier: "
<< scaleOutput_[i] << nl;
}
}
}
}
@ -638,6 +724,8 @@ bool Foam::lumpedPointMovement::readState()
coupler().resolveFile(inputName_)
);
state_.scalePoints(scaleInput_[scalingType::LENGTH]);
state_.relax(relax_, prev);
return status;
@ -646,45 +734,114 @@ bool Foam::lumpedPointMovement::readState()
bool Foam::lumpedPointMovement::writeData
(
const UList<vector>& forces
Ostream& os,
const UList<vector>& forces,
const UList<vector>& moments,
const outputFormatType fmt,
const Time* timeinfo
) const
{
if (!Pstream::master())
const bool writeMoments = (moments.size() == forces.size());
if (fmt == outputFormatType::PLAIN)
{
return false;
}
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output); // ASCII
if (outputFormat_ == outputFormatType::PLAIN)
{
os <<"# output from OpenFOAM" << nl
<<"# N, points, forces" << nl
<< this->size() << nl;
const char* zeroVector = "0 0 0";
forAll(locations_, i)
os <<"########" << nl;
if (timeinfo)
{
const vector pos = locations_[i] * axis_;
os <<"# ";
putTime(os, *timeinfo) << nl;
}
os <<"# size=" << this->size() << nl
<<"# columns (points) (forces)";
os << pos.x() << ' '
<< pos.y() << ' '
<< pos.z() << ' ';
if (writeMoments)
{
os << " (moments)";
}
if (i < forces.size())
os << nl;
bool report = false;
scalar scaleLength = scaleOutput_[scalingType::LENGTH];
scalar scaleForce = scaleOutput_[scalingType::FORCE];
scalar scaleMoment = scaleOutput_[scalingType::MOMENT];
if (scaleLength > 0)
{
report = true;
}
else
{
scaleLength = 1.0;
}
if (scaleForce > 0)
{
report = true;
}
else
{
scaleForce = 1.0;
}
if (writeMoments)
{
if (scaleMoment > 0)
{
os << forces[i].x() << ' '
<< forces[i].y() << ' '
<< forces[i].z();
report = true;
}
else
{
os << zeroVector;
scaleMoment = 1.0;
}
}
if (report)
{
os <<"# scaling points=" << scaleLength
<<" forces=" << scaleForce;
if (writeMoments)
{
os <<" moments=" << scaleMoment;
}
os << nl;
os << nl;
}
os <<"########" << nl;
forAll(locations_, i)
{
const vector pos = scaleLength * (locations_[i] * axis_);
putPlain(os, pos) << ' ';
if (i < forces.size())
{
const vector val(scaleForce * forces[i]);
putPlain(os, val);
}
else
{
putPlain(os, vector::zero);
}
if (writeMoments)
{
os << ' ';
if (i < moments.size())
{
const vector val(scaleMoment * moments[i]);
putPlain(os, val);
}
else
{
putPlain(os, vector::zero);
}
}
os << nl;
}
}
else
@ -693,10 +850,21 @@ bool Foam::lumpedPointMovement::writeData
// - exclude the usual OpenFOAM 'FoamFile' header
// - ensure lists have consistent format
os <<"// output from OpenFOAM" << nl << nl;
os <<"////////" << nl;
if (timeinfo)
{
os <<"// ";
putTime(os, *timeinfo) << nl;
}
os << nl;
writeList(os, "points", (locations_*axis_)());
writeList(os, "forces", forces);
if (writeMoments)
{
writeList(os, "moments", moments);
}
}
return true;
@ -706,7 +874,8 @@ bool Foam::lumpedPointMovement::writeData
bool Foam::lumpedPointMovement::writeData
(
const UList<vector>& forces,
const UList<vector>& moments
const UList<vector>& moments,
const Time* timeinfo
) const
{
if (!Pstream::master())
@ -714,60 +883,28 @@ bool Foam::lumpedPointMovement::writeData
return false;
}
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output); // ASCII
if (outputFormat_ == outputFormatType::PLAIN)
// Regular output
{
os <<"# output from OpenFOAM" << nl
<<"# N, points, forces, moments" << nl
<< this->size() << nl;
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output, IOstream::ASCII);
const char* zeroVector = "0 0 0";
forAll(locations_, i)
{
const vector pos = locations_[i] * axis_;
os << pos.x() << ' '
<< pos.y() << ' '
<< pos.z() << ' ';
if (i < forces.size())
{
os << forces[i].x() << ' '
<< forces[i].y() << ' '
<< forces[i].z() << ' ';
}
else
{
os << zeroVector << ' ';
}
if (i < moments.size())
{
os << moments[i].x() << ' '
<< moments[i].y() << ' '
<< moments[i].z();
}
else
{
os << zeroVector;
}
os << nl;
}
writeData(os, forces, moments, outputFormat_, timeinfo);
}
else
// Log output
{
// Make it easier for external programs to parse
// - exclude the usual OpenFOAM 'FoamFile' header
// - ensure lists have consistent format
const fileName output(coupler().resolveFile(logName_));
os <<"// output from OpenFOAM" << nl << nl;
OFstream os
(
output,
IOstream::ASCII,
IOstream::currentVersion,
IOstream::UNCOMPRESSED,
true // append mode
);
writeList(os, "points", (locations_*axis_)());
writeList(os, "forces", forces);
writeList(os, "moments", moments);
writeData(os, forces, moments, outputFormatType::PLAIN, timeinfo);
}
return true;

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -60,8 +60,10 @@ SourceFiles
namespace Foam
{
// Forward declarations
class polyMesh;
class Time;
/*---------------------------------------------------------------------------*\
Class lumpedPointMovement Declaration
@ -78,11 +80,22 @@ public:
DICTIONARY
};
//- Output format types
enum scalingType
{
LENGTH = 0,
FORCE,
MOMENT
};
// Static data
//- Names for the output format types
static const Enum<outputFormatType> formatNames;
//- Names for the scaling types
static const Enum<scalingType> scalingNames;
private:
@ -125,9 +138,15 @@ private:
//- File io
word inputName_;
word outputName_;
word logName_;
lumpedPointState::inputFormatType inputFormat_;
outputFormatType outputFormat_;
//- Optional scale factors for input/output files
FixedList<scalar, 1> scaleInput_;
FixedList<scalar, 3> scaleOutput_;
// Demand-driven private data
@ -246,6 +265,9 @@ public:
//- The output (forces) file name
inline const word& outputName() const;
//- The log file name
inline const word& logName() const;
//- The input (state) file format
inline lumpedPointState::inputFormatType inputFormat() const;
@ -324,21 +346,24 @@ public:
//- Write axis, locations, division as a dictionary
void writeDict(Ostream& os) const;
//- Write points, forces
//- Write points, forces, moments. Only call from the master process
bool writeData
(
const UList<vector>& forces
Ostream& os,
const UList<vector>& forces,
const UList<vector>& moments,
const outputFormatType fmt = outputFormatType::PLAIN,
const Time* timeinfo = nullptr
) const;
//- Write points, forces, moments
bool writeData
(
const UList<vector>& forces,
const UList<vector>& moments
const UList<vector>& moments = List<vector>(),
const Time* timeinfo = nullptr
) const;
//- Read state from file, applying relaxation as requested
bool readState();

View File

@ -0,0 +1,100 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: plus |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object lumpedPointMovement;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Reference axis for the locations
axis (0 0 1);
// Locations of the lumped points
locations 11(0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5);
// Division for pressure forces (0-1)
division 0.5;
//- If present, the offset of patch points compared to the locations
// Otherwise determined from the bounding box
// centre (0 0 0);
//- The interpolation scheme
interpolationScheme linear;
//- Relaxation/scaling factor when updating positions
relax 1.0;
forces
{
//- The pressure name (default: p)
p p;
//- Reference pressure [Pa] (default: 0)
pRef 0;
//- Reference density for incompressible calculations (default: 1)
rhoRef 1;
}
communication
{
commsDir "comms";
log on;
waitInterval 1;
timeOut 100;
initByExternal false;
// Input file of positions/rotation, written by external application
inputName positions.in;
// Output file of forces, written by OpenFOAM
outputName forces.out;
// Log of points/forces/moments during the simulation
logName movement.log;
inputFormat dictionary;
outputFormat dictionary;
debugTable "$FOAM_CASE/output.txt";
// Scaling applied to values read from 'inputName'
scaleInput
{
//- Length multiplier (to metres). Eg 0.001 for [mm] -> [m]
length 1;
}
// Scaling applied to values written to 'outputName'
scaleOutput
{
//- Length multiplier (from metres). Eg 1000 for [m] -> [mm]
length 1;
//- Force units multiplier (from Pa)
force 1;
//- Moment units multiplier (from N.m)
moment 1;
}
}
// ************************************************************************* //

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -133,6 +133,12 @@ inline const Foam::word& Foam::lumpedPointMovement::outputName() const
}
inline const Foam::word& Foam::lumpedPointMovement::logName() const
{
return logName_;
}
inline Foam::lumpedPointState::inputFormatType
Foam::lumpedPointMovement::inputFormat() const
{

Some files were not shown because too many files have changed in this diff Show More