/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2015 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify i 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 . \*---------------------------------------------------------------------------*/ #include "externalCoupledFunctionObject.H" #include "OSspecific.H" #include "IFstream.H" #include "OFstream.H" #include "volFields.H" #include "externalCoupledMixedFvPatchFields.H" #include "mixedFvPatchFields.H" #include "fixedGradientFvPatchFields.H" #include "fixedValueFvPatchFields.H" #include "OStringStream.H" #include "globalIndex.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template bool Foam::externalCoupledFunctionObject::readData ( const UPtrList& meshes, const wordRe& groupName, const word& fieldName ) { typedef GeometricField volFieldType; typedef externalCoupledMixedFvPatchField patchFieldType; wordList regionNames(meshes.size()); forAll(meshes, i) { regionNames[i] = meshes[i].dbDir(); } // File only opened on master; contains data for all processors, for all // patchIDs. autoPtr masterFilePtr; if (Pstream::master()) { const fileName transferFile ( groupDir(commsDir_, compositeName(regionNames), groupName) / fieldName + ".in" ); if (log_) { Info<< type() << ": reading data from " << transferFile << endl; } masterFilePtr.reset(new IFstream(transferFile)); if (!masterFilePtr().good()) { FatalIOErrorIn ( "void externalCoupledFunctionObject::readData" "(" "const UPtrList&, " "const wordRe&, " "const word&" ")", masterFilePtr() ) << "Cannot open file for region " << compositeName(regionNames) << ", field " << fieldName << exit(FatalIOError); } } label nFound = 0; forAll(meshes, i) { const fvMesh& mesh = meshes[i]; if (!mesh.foundObject(fieldName)) { continue; } nFound++; const volFieldType& cvf = mesh.lookupObject(fieldName); const typename volFieldType::GeometricBoundaryField& bf = cvf.boundaryField(); // Get the patches const labelList patchIDs ( mesh.boundaryMesh().patchSet ( List(1, groupName) ).sortedToc() ); // Handle column-wise reading of patch data. Supports most easy types forAll(patchIDs, i) { label patchI = patchIDs[i]; if (isA(bf[patchI])) { // Explicit handling of externalCoupledMixed bcs - they // have specialised reading routines. patchFieldType& pf = const_cast ( refCast ( bf[patchI] ) ); // Read from master into local stream OStringStream os; readLines ( bf[patchI].size(), // number of lines to read masterFilePtr, os ); // Pass responsability for all reading over to bc pf.readData(IStringStream(os.str())()); // Update the value from the read coefficicient. Bypass any // additional processing by derived type. pf.patchFieldType::evaluate(); } else if (isA >(bf[patchI])) { // Read columns from file for // value, snGrad, refValue, refGrad, valueFraction List data; readColumns ( bf[patchI].size(), // number of lines to read 4*pTraits::nComponents+1, // nColumns: 4*Type+1*scalar masterFilePtr, data ); mixedFvPatchField& pf = const_cast&> ( refCast > ( bf[patchI] ) ); // Transfer read data to bc. // Skip value, snGrad direction columnI = 2*pTraits::nComponents; Field& refValue = pf.refValue(); for ( direction cmpt = 0; cmpt < pTraits::nComponents; cmpt++ ) { refValue.replace(cmpt, data[columnI++]); } Field& refGrad = pf.refGrad(); for ( direction cmpt = 0; cmpt < pTraits::nComponents; cmpt++ ) { refGrad.replace(cmpt, data[columnI++]); } pf.valueFraction() = data[columnI]; // Update the value from the read coefficicient. Bypass any // additional processing by derived type. pf.mixedFvPatchField::evaluate(); } else if (isA >(bf[patchI])) { // Read columns for value and gradient List data; readColumns ( bf[patchI].size(), // number of lines to read 2*pTraits::nComponents, // nColumns: Type masterFilePtr, data ); fixedGradientFvPatchField& pf = const_cast&> ( refCast > ( bf[patchI] ) ); // Transfer gradient to bc Field& gradient = pf.gradient(); for ( direction cmpt = 0; cmpt < pTraits::nComponents; cmpt++ ) { gradient.replace ( cmpt, data[pTraits::nComponents+cmpt] ); } // Update the value from the read coefficicient. Bypass any // additional processing by derived type. pf.fixedGradientFvPatchField::evaluate(); } else if (isA >(bf[patchI])) { // Read columns for value only List data; readColumns ( bf[patchI].size(), // number of lines to read pTraits::nComponents, // number of columns to read masterFilePtr, data ); // Transfer read value to bc Field value(bf[patchI].size()); for ( direction cmpt = 0; cmpt < pTraits::nComponents; cmpt++ ) { value.replace(cmpt, data[cmpt]); } fixedValueFvPatchField& pf = const_cast&> ( refCast > ( bf[patchI] ) ); pf == value; // Update the value from the read coefficicient. Bypass any // additional processing by derived type. pf.fixedValueFvPatchField::evaluate(); } else { FatalErrorIn ( "void externalCoupledFunctionObject::readData" "(" "const UPtrList&, " "const wordRe&, " "const word&" ")" ) << "Unsupported boundary condition " << bf[patchI].type() << " for patch " << bf[patchI].patch().name() << " in region " << mesh.name() << exit(FatalError); } initialised_ = true; } } return nFound > 0; } template Foam::tmp > Foam::externalCoupledFunctionObject::gatherAndCombine ( const Field& fld ) { // Collect values from all processors List > gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = fld; Pstream::gatherList(gatheredValues); tmp > tresult(new Field(0)); Field& result = tresult(); if (Pstream::master()) { // Combine values into single field label globalElemI = 0; forAll(gatheredValues, lstI) { globalElemI += gatheredValues[lstI].size(); } result.setSize(globalElemI); globalElemI = 0; forAll(gatheredValues, lstI) { const Field& sub = gatheredValues[lstI]; forAll(sub, elemI) { result[globalElemI++] = sub[elemI]; } } } return tresult; } template bool Foam::externalCoupledFunctionObject::writeData ( const UPtrList& meshes, const wordRe& groupName, const word& fieldName ) const { typedef GeometricField volFieldType; typedef externalCoupledMixedFvPatchField patchFieldType; wordList regionNames(meshes.size()); forAll(meshes, i) { regionNames[i] = meshes[i].dbDir(); } // File only opened on master; contains data for all processors, for all // patchIDs autoPtr masterFilePtr; if (Pstream::master()) { const fileName transferFile ( groupDir(commsDir_, compositeName(regionNames), groupName) / fieldName + ".out" ); if (log_) { Info<< type() << ": writing data to " << transferFile << endl; } masterFilePtr.reset(new OFstream(transferFile)); if (!masterFilePtr().good()) { FatalIOErrorIn ( "externalCoupledFunctionObject::writeData" "(" "const UPtrList&, " "const wordRe&, " "const word&" ") const", masterFilePtr() ) << "Cannot open file for region " << compositeName(regionNames) << ", field " << fieldName << exit(FatalIOError); } } bool headerDone = false; label nFound = 0; forAll(meshes, i) { const fvMesh& mesh = meshes[i]; if (!mesh.foundObject(fieldName)) { continue; } nFound++; const volFieldType& cvf = mesh.lookupObject(fieldName); const typename volFieldType::GeometricBoundaryField& bf = cvf.boundaryField(); // Get the patches const labelList patchIDs ( mesh.boundaryMesh().patchSet ( List(1, groupName) ).sortedToc() ); // Handle column-wise writing of patch data. Supports most easy types forAll(patchIDs, i) { label patchI = patchIDs[i]; const globalIndex globalFaces(bf[patchI].size()); if (isA(bf[patchI])) { // Explicit handling of externalCoupledMixed bcs - they // have specialised writing routines const patchFieldType& pf = refCast ( bf[patchI] ); OStringStream os; // Pass responsibility for all writing over to bc pf.writeData(os); // Collect contributions from all processors and output them on // master if (Pstream::master()) { // Output master data first if (!headerDone) { pf.writeHeader(masterFilePtr()); headerDone = true; } masterFilePtr() << os.str().c_str(); for (label procI = 1; procI < Pstream::nProcs(); procI++) { IPstream fromSlave(Pstream::scheduled, procI); string str(fromSlave); masterFilePtr() << str.c_str(); } } else { OPstream toMaster(Pstream::scheduled, Pstream::masterNo()); toMaster << os.str(); } } else if (isA >(bf[patchI])) { const mixedFvPatchField& pf = refCast >(bf[patchI]); Field value(gatherAndCombine(pf)); Field snGrad(gatherAndCombine(pf.snGrad()())); Field refValue(gatherAndCombine(pf.refValue())); Field refGrad(gatherAndCombine(pf.refGrad())); scalarField valueFraction(gatherAndCombine(pf.valueFraction())); if (Pstream::master()) { forAll(refValue, faceI) { masterFilePtr() << value[faceI] << token::SPACE << snGrad[faceI] << token::SPACE << refValue[faceI] << token::SPACE << refGrad[faceI] << token::SPACE << valueFraction[faceI] << nl; } } } else { // Output the value and snGrad Field value(gatherAndCombine(bf[patchI])); Field snGrad(gatherAndCombine(bf[patchI].snGrad()())); if (Pstream::master()) { forAll(value, faceI) { masterFilePtr() << value[faceI] << token::SPACE << snGrad[faceI] << nl; } } } } } return nFound > 0; } // ************************************************************************* //