foamVtkFvMeshAdaptor.C 9.63 KB
Newer Older
1
2
3
4
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
5
    \\  /    A nd           | Copyright (C) 2017-2019 OpenCFD Ltd.
Mark Olesen's avatar
Mark Olesen committed
6
     \\/     M anipulation  |
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
-------------------------------------------------------------------------------
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 "foamVtkFvMeshAdaptor.H"
#include "Pstream.H"

// OpenFOAM includes
#include "fvMesh.H"

// VTK includes
#include <vtkMultiBlockDataSet.h>
#include <vtkMultiPieceDataSet.h>
#include <vtkSmartPointer.h>
#include <vtkInformation.h>

// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //

namespace Foam
{
namespace vtk
{
    defineTypeNameAndDebug(fvMeshAdaptor, 0);
}
46
47
} // End namespace Foam

48
49
50

const Foam::Enum
<
51
    Foam::vtk::fvMeshAdaptor::channelType
52
53
54
>
Foam::vtk::fvMeshAdaptor::channelNames
{
55
56
57
58
    { channelType::NONE,     "none" },
    { channelType::INTERNAL, "internal" },
    { channelType::BOUNDARY, "boundary" },
    { channelType::ALL,      "all" },
59
60
61
};


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //

void Foam::vtk::fvMeshAdaptor::definePatchIds()
{
    // Generate or update the list of patchIds

    patchIds_.clear();

    if (!usingBoundary())
    {
        return;
    }

    // General patch information
    // Restrict to non-processor patches.
    // This value is invariant across all processors.

    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
    const label nNonProcessor = patches.nNonProcessor();

    if (patchPatterns_.empty())
    {
        patchIds_ = identity(nNonProcessor);
    }
    else
    {
88
89
        // Don't warn if not found, use patch groups
        labelHashSet ids(patches.patchSet(patchPatterns_, false, true));
90
91
92
93

        // Restricted to non-processor patches
        ids.filterKeys
        (
94
            [nNonProcessor](label i){ return i < nNonProcessor; }
95
96
97
98
99
100
101
102
        );

        // MUST be sorted. Other internal logic relies upon this!
        patchIds_ = ids.sortedToc();
    }
}


103
104
105
106
// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

Foam::vtk::fvMeshAdaptor::fvMeshAdaptor
(
107
    const fvMesh& mesh,
108
109
    const channelType channelsOpt,
    const wordRes& patchSelection
110
111
112
)
:
    mesh_(mesh),
113
114
115
    patchPatterns_(patchSelection),
    patchIds_(),
    channels_(channelsOpt),
116
117
    interpFields_(true),
    extrapPatches_(false),
118
    decomposePoly_(false),
119
120
121
122
123
124
    meshState_(polyMesh::TOPO_CHANGE)
{}


// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //

125
void Foam::vtk::fvMeshAdaptor::setChannels(const wordList& chanNames)
126
{
127
128
    unsigned chanIds = 0;
    for (const word& chan : chanNames)
129
130
131
    {
        if (channelNames.found(chan))
        {
132
            chanIds |= channelNames[chan];
133
134
135
        }
    }

136
    setChannels(chanIds);
137
138
139
}


140
void Foam::vtk::fvMeshAdaptor::setChannels(enum channelType chanIds)
141
142
143
144
145
146
147
148
149
150
151
{
    channels_ = chanIds;

    if (!usingInternal())
    {
        cachedVtu_.clear();
    }

    if (!usingBoundary())
    {
        cachedVtp_.clear();
152
        patchIds_.clear();
153
154
155
156
    }
}


157
void Foam::vtk::fvMeshAdaptor::setChannels(unsigned chanIds)
158
{
159
    channels_ = (chanIds & 0x3);
160

161
    if (!usingInternal())
162
163
164
165
    {
        cachedVtu_.clear();
    }

166
    if (!usingBoundary())
167
168
    {
        cachedVtp_.clear();
169
170
171
172
173
174
175
176
177
178
179
        patchIds_.clear();
    }
}


void Foam::vtk::fvMeshAdaptor::setDecompose(const bool val)
{
    if (usingInternal() && val != decomposePoly_)
    {
        cachedVtu_.clear();
        decomposePoly_ = val;
180
181
182
183
    }
}


184
185
186
187
188
189
Foam::label Foam::vtk::fvMeshAdaptor::channels() const
{
    return label(channels_);
}


190
bool Foam::vtk::fvMeshAdaptor::usingInternal() const
191
{
192
    return (channels_ & INTERNAL);
193
194
195
}


196
bool Foam::vtk::fvMeshAdaptor::usingBoundary() const
197
{
198
    return (channels_ & BOUNDARY);
199
200
201
}


202
const Foam::labelList& Foam::vtk::fvMeshAdaptor::patchIds() const
203
{
204
    return patchIds_;
205
206
207
208
209
210
211
}


void Foam::vtk::fvMeshAdaptor::updateContent(const wordRes& selectFields)
{
    const bool oldDecomp = decomposePoly_;

212
213
214
215
216
217
218
219
    // General patch information
    // Restrict to non-processor patches.
    // This value is invariant across all processors.

    const polyBoundaryMesh& patches = mesh_.boundaryMesh();
    const label nNonProcessor = patches.nNonProcessor();


220
221
222
223
    // Update cached, saved, unneed values.

    HashSet<string> nowActive;

224
225
    // INTERNAL
    if (usingInternal())
226
    {
227
        nowActive.insert(internalName());
228
229
230
    }


231
232
    // BOUNDARY
    if (usingBoundary())
233
    {
234
235
236
237
238
        for (label patchId=0; patchId < nNonProcessor; ++patchId)
        {
            const polyPatch& pp = patches[patchId];
            nowActive.insert(pp.name());
        }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    }

    // Dispose of unneeded components
    cachedVtp_.retain(nowActive);
    cachedVtu_.retain(nowActive);

    if
    (
        meshState_ == polyMesh::TOPO_CHANGE
     || meshState_ == polyMesh::TOPO_PATCH_CHANGE
    )
    {
        // Eliminate cached values that would be unreliable
        forAllIters(cachedVtp_, iter)
        {
254
255
            iter.val().clearGeom();
            iter.val().clear();
256
257
258
        }
        forAllIters(cachedVtu_, iter)
        {
259
260
            iter.val().clearGeom();
            iter.val().clear();
261
        }
262
263

        definePatchIds();
264
265
266
267
268
269
    }
    else if (oldDecomp != decomposePoly_)
    {
        // poly-decompose changed - dispose of cached values
        forAllIters(cachedVtu_, iter)
        {
270
271
            iter.val().clearGeom();
            iter.val().clear();
272
273
274
275
        }
    }

    convertGeometryInternal();
276
277
    convertGeometryBoundary();

278
    applyGhosting();
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    convertVolFields(selectFields);
    meshState_ = polyMesh::UNCHANGED;
}


vtkSmartPointer<vtkMultiBlockDataSet>
Foam::vtk::fvMeshAdaptor::output(const wordRes& select)
{
    updateContent(select);

    // All individual datasets are vtkMultiPieceDataSet for improved
    // handling downstream.

    label rank = 0;
    label nproc = 1;

    if (Pstream::parRun())
    {
        rank  = Pstream::myProcNo();
        nproc = Pstream::nProcs();
    }


    auto outputs = vtkSmartPointer<vtkMultiBlockDataSet>::New();

304
    unsigned int blockNo = 0;
305

306
307
308
    // INTERNAL
    if (usingInternal())
    {
309
310
        do
        {
311
            const auto& longName = internalName();
312
            auto iter = cachedVtu_.find(longName);
313
            if (!iter.found() || !iter.val().dataset)
314
            {
315
                Pout<<"Cache miss for VTU " << longName << endl;
316
317
318
                break; // Should never happen
            }

319
            foamVtuData& vtuData = iter.val();
320
321
322
323
324
325
326
327
328
329
330

            auto pieces = vtkSmartPointer<vtkMultiPieceDataSet>::New();

            pieces->SetNumberOfPieces(nproc);
            pieces->SetPiece(rank, vtuData.dataset);

            outputs->SetBlock(blockNo, pieces);

            outputs->GetMetaData(blockNo)->Set
            (
                vtkCompositeDataSet::NAME(),
331
                internalName()
332
333
334
335
336
337
            );

            ++blockNo;
        } while (false);  // do once
    }

338
    // BOUNDARY
339
    if (!patchIds_.empty())
340
    {
341
        unsigned int subBlockNo = 0;
342
343
344
345
346

        auto output = vtkSmartPointer<vtkMultiBlockDataSet>::New();

        const polyBoundaryMesh& patches = mesh_.boundaryMesh();

347
        for (const label patchId : patchIds_)
348
349
350
351
352
        {
            const polyPatch& pp = patches[patchId];
            const word& longName = pp.name();

            auto iter = cachedVtp_.find(longName);
353
            if (!iter.found() || !iter.val().dataset)
354
            {
355
                Pout<<"Cache miss for VTP patch " << longName << endl;
356
357
358
                break; // Should never happen
            }

359
            foamVtpData& vtpData = iter.val();
360
361
362
363
364
365

            auto pieces = vtkSmartPointer<vtkMultiPieceDataSet>::New();

            pieces->SetNumberOfPieces(nproc);
            pieces->SetPiece(rank, vtpData.dataset);

366
            output->SetBlock(subBlockNo, pieces);
367

368
            output->GetMetaData(subBlockNo)->Set
369
370
371
372
373
            (
                vtkCompositeDataSet::NAME(),
                longName
            );

374
            ++subBlockNo;
375
376
        }

377
378
379
        outputs->SetBlock(blockNo, output);

        outputs->GetMetaData(blockNo)->Set
380
381
        (
            vtkCompositeDataSet::NAME(),
382
            boundaryName()
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
        );
    }

    // Would actually like to have this:
    //     outputs->SetName(mesh_.name().c_str());
    // but do that in the caller side

    return outputs;
}


void Foam::vtk::fvMeshAdaptor::updateState(polyMesh::readUpdateState state)
{
    // Only move to worse states
    switch (state)
    {
        case polyMesh::UNCHANGED:
            break;

        case polyMesh::POINTS_MOVED:
            if (meshState_ == polyMesh::UNCHANGED)
            {
                meshState_ = polyMesh::POINTS_MOVED;
            }
            break;

        case polyMesh::TOPO_CHANGE:
        case polyMesh::TOPO_PATCH_CHANGE:
            meshState_ = polyMesh::TOPO_CHANGE;
            break;
    }
}


// ************************************************************************* //