/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2022-2024 OpenCFD Ltd. ------------------------------------------------------------------------------- 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 . \*---------------------------------------------------------------------------*/ // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated ( const bool writeTracks ) { // Collated? // ======== // CaseFile: rootdir/NAME/NAME.case // Geometry: rootdir/NAME/NAME.mesh wroteGeom_ = true; return fileName::null; } template Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated ( const word& fieldName, const UPtrList>& fieldPtrs, elemOutputType elemOutput ) { // Geometry changed since last output? Capture now const bool geomChanged = (!upToDate_); checkOpen(); const ensight::FileName baseName(outputPath_.name()); const ensight::VarName varName(fieldName); // Collated // ======== // CaseFile: rootdir/NAME/NAME.case // Geometry: rootdir/NAME/data//geometry // Field: rootdir/NAME/data//field // Use geometry name as sub-directory for results. Eg, // - NAME1/NAME1.case // - NAME1/data/00000000/geometry // - NAME1/data/00000000/VAR1 // - NAME1/data/00000000/VAR2 // Names "data" and "geometry" as per ensightCase: const int maskWidth = 8; const char* mask = "data/********/"; // Ignore the useTimeDir setting - manage ourselves const fileName baseDir = outputPath_; const word timeDir = timeName(); const scalar timeValue = currTime_.value(); const fileName outputFile = baseDir / baseName + ".case"; if (verbose_) { Info<< "Writing case file to " << outputFile << endl; } // Update geometry merge(); { if (!Foam::isDir(outputFile.path())) { Foam::mkDir(outputFile.path()); } const bool stateChanged = caching_.update ( baseDir, timeValue, geomChanged, fieldName, ensightPTraits::typeName, varName ); // The most current time and geometry indices const label timeIndex = caching_.latestTimeIndex(); const label geomIndex = caching_.latestGeomIndex(); // This will be used for the name of a static geometry, // or just the masking part for moving geometries. const fileName geometryName ( "data" / ensightCase::padded(maskWidth, geomIndex) / ensightCase::geometryName ); // Location for data (and possibly the geometry as well) const fileName dataDir ( baseDir/"data"/ensightCase::padded(maskWidth, timeIndex) ); // As per mkdir -p "data/00000000" Foam::mkDir(dataDir); const fileName geomFile(baseDir/geometryName); if (!Foam::exists(geomFile)) { if (verbose_) { Info<< "Writing geometry to " << geomFile.name() << endl; } // Two-argument form for path-name to avoid validating base-dir ensightGeoFile osGeom ( geomFile.path(), geomFile.name(), caseOpts_.format() ); osGeom.beginGeometry(); writeGeometry(osGeom, elemOutput); } // Write field ensightFile osField ( dataDir, varName, caseOpts_.format() ); if (verbose_) { Info<< "Writing field file to " << osField.name() << endl; } // Write field (serial only) writeTrackField(osField, fieldPtrs); // Update case file if (stateChanged) { OFstream osCase ( IOstreamOption::ATOMIC, outputFile, IOstreamOption::ASCII ); ensightCase::setTimeFormat(osCase, caseOpts_); // time-format if (verbose_) { Info<< "Writing case file to " << osCase.name() << endl; } // The geometry can be any of the following: // 0: constant/static // 1: moving, with the same frequency as the data // 2: moving, with different frequency as the data const label tsGeom = caching_.geometryTimeset(); osCase << "FORMAT" << nl << "type: ensight gold" << nl << nl << "GEOMETRY" << nl; if (tsGeom) { // moving osCase << "model: " << tsGeom << " " // time-set (1|2) << mask << geometryName.name() << nl; } else { // steady osCase << "model: " << geometryName.c_str() << nl; } osCase << nl << "VARIABLE" << nl; for (const entry& dEntry : caching_.fieldsDict()) { const dictionary& subDict = dEntry.dict(); const string varType(subDict.get("type")); const word varName ( subDict.getOrDefault ( "name", dEntry.keyword() // fieldName as fallback ) ); osCase << varType.c_str() << ( true // this->isPointData() ? " per node: 1 " // time-set 1 : " per element: 1 " // time-set 1 ) << setw(15) << varName << ' ' << mask << ensight::FileName(varName).c_str() << nl; } osCase << nl << "TIME" << nl; ensightCase::printTimeset(osCase, 1, caching_.times()); if (tsGeom == 2) { ensightCase::printTimeset ( osCase, tsGeom, caching_.times(), caching_.geometries() ); } osCase << "# end" << nl; } // Timestamp in the directory for future reference { OFstream timeStamp(dataDir/"time"); timeStamp << "# timestep time" << nl << dataDir.name() << ' ' << timeValue << nl; } } wroteGeom_ = true; return outputFile; } // ************************************************************************* //