/*---------------------------------------------------------------------------*\ ========= | \\ / 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 fvMesh& mesh, const wordRe& groupName, const labelList& patchIDs, const word& fieldName ) { typedef GeometricField volFieldType; typedef externalCoupledMixedFvPatchField patchFieldType; if (!mesh.foundObject(fieldName)) { return false; } const volFieldType& cvf = mesh.lookupObject(fieldName); const typename volFieldType::GeometricBoundaryField& bf = cvf.boundaryField(); // File only opened on master; contains data for all processors, for all // patchIDs. autoPtr masterFilePtr; if (Pstream::master()) { const fileName transferFile ( groupDir(commsDir_, mesh.dbDir(), 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 fvMesh&, " "const wordRe&, " "const labelList&, " "const word&" ")", masterFilePtr() ) << "Cannot open file for region " << mesh.name() << ", field " << fieldName << ", patches " << patchIDs << exit(FatalIOError); } } // 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 externalCoupledObjectMixed 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 fvMesh&, " "const wordRe&, " "const labelList&, " "const word&" ")" ) << "Unsupported boundary condition " << bf[patchI].type() << " for patch " << bf[patchI].patch().name() << " in region " << mesh.name() << exit(FatalError); } initialised_ = true; } return true; } 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 fvMesh& mesh, const wordRe& groupName, const labelList& patchIDs, const word& fieldName ) const { typedef GeometricField volFieldType; typedef externalCoupledMixedFvPatchField patchFieldType; if (!mesh.foundObject(fieldName)) { return false; } const volFieldType& cvf = mesh.lookupObject(fieldName); const typename volFieldType::GeometricBoundaryField& bf = cvf.boundaryField(); // File only opened on master; contains data for all processors, for all // patchIDs autoPtr masterFilePtr; if (Pstream::master()) { const fileName transferFile ( groupDir(commsDir_, mesh.dbDir(), groupName) / fieldName + ".out" ); if (log_) { Info<< type() << ": writing data to " << transferFile << endl; } masterFilePtr.reset(new OFstream(transferFile)); if (!masterFilePtr().good()) { FatalIOErrorIn ( "externalCoupledFunctionObject::writeData" "(" "const fvMesh&, " "const wordRe&, " "const labelList&, " "const word&" ") const", masterFilePtr() ) << "Cannot open file for region " << mesh.name() << ", field " << fieldName << ", patches " << patchIDs << exit(FatalIOError); } } bool headerDone = false; // 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 externalCoupledObjectMixed 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 true; } // ************************************************************************* //