vtkPVFoamFieldTemplates.C 26 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.
6 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
     \\/     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/>.

InClass
    vtkPVFoam

\*---------------------------------------------------------------------------*/

#ifndef vtkPVFoamFieldTemplates_C
#define vtkPVFoamFieldTemplates_C

// OpenFOAM includes
33
#include "error.H"
34 35 36 37 38 39
#include "emptyFvPatchField.H"
#include "wallPolyPatch.H"
#include "faceSet.H"
#include "volPointInterpolation.H"
#include "zeroGradientFvPatchField.H"
#include "interpolatePointToCell.H"
40 41
#include "areaFaMesh.H"
#include "areaFields.H"
42

43 44 45 46 47
// VTK includes
#include <vtkFloatArray.h>
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkSmartPointer.h>
48 49 50 51 52 53 54 55 56 57

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//
// volume-fields
//

template<class Type>
void Foam::vtkPVFoam::convertVolField
(
    const PtrList<patchInterpolator>& patchInterpList,
58
    const GeometricField<Type, fvPatchField, volMesh>& fld
59 60 61 62 63 64 65 66 67 68 69 70
)
{
    const fvMesh& mesh = fld.mesh();
    const polyBoundaryMesh& patches = mesh.boundaryMesh();

    const bool interpField = !patchInterpList.empty();
    const bool extrapPatch = reader_->GetExtrapolatePatches();

    // Interpolated field (demand driven)
    autoPtr<GeometricField<Type, pointPatchField, pointMesh>> ptfPtr;
    if (interpField)
    {
71 72
        DebugInfo
            << "convertVolField interpolating:" << fld.name() << nl;
73 74 75 76 77 78 79

        ptfPtr.reset
        (
            volPointInterpolation::New(mesh).interpolate(fld).ptr()
        );
    }

80 81 82 83
    convertVolFieldBlock(fld, ptfPtr, rangeVolume_);    // internalMesh
    convertVolFieldBlock(fld, ptfPtr, rangeCellZones_); // cellZones
    convertVolFieldBlock(fld, ptfPtr, rangeCellSets_);  // cellSets

84
    // Patches - currently skip field conversion for groups
85 86 87 88 89
    for
    (
        const auto partId
      : rangePatches_.intersection(selectedPartIds_)
    )
90
    {
91
        const auto& longName = selectedPartIds_[partId];
92

93
        auto iter = cachedVtp_.find(longName);
94
        if (!iter.found() || !iter.val().dataset)
95
        {
96
            // Should not happen, but for safety require a vtk geometry
97 98
            continue;
        }
99

100
        foamVtpData& vtpData = iter.val();
101
        auto dataset = vtpData.dataset;
102

103
        const labelUList& patchIds = vtpData.additionalIds();
104

105
        if (patchIds.empty())
106 107 108 109
        {
            continue;
        }

110 111 112 113 114 115 116 117
        // This is slightly roundabout, but we deal with groups and with
        // single patches.
        // For groups (spanning several patches) it is fairly messy to
        // get interpolated point fields. We would need to create a indirect
        // patch each time to obtain the mesh points. We thus skip that.
        //
        // To improve code reuse, we allocate the CellData as a zeroed-field
        // ahead of time.
118

119
        vtkSmartPointer<vtkFloatArray> cdata = vtk::Tools::zeroField<Type>
120
        (
121 122 123 124 125 126 127 128 129
            fld.name(),
            dataset->GetNumberOfPolys()
        );

        vtkSmartPointer<vtkFloatArray> pdata;
        const bool allowPdata = (interpField && patchIds.size() == 1);

        label coffset = 0; // the write offset into cell-data
        for (label patchId : patchIds)
130
        {
131
            const fvPatchField<Type>& ptf = fld.boundaryField()[patchId];
132

133
            if
134
            (
135 136
                isType<emptyFvPatchField<Type>>(ptf)
             ||
137
                (
138 139 140 141
                    extrapPatch
                 && !polyPatch::constraintType(patches[patchId].type())
                )
            )
142
            {
143
                fvPatch p(ptf.patch().patch(), mesh.boundary());
144

145
                tmp<Field<Type>> tpptf
146
                (
147
                    fvPatchField<Type>(p, fld).patchInternalField()
148
                );
149

150 151
                coffset +=
                    vtk::Tools::transcribeFloatData(cdata, tpptf(), coffset);
152

153 154
                if (allowPdata && patchId < patchInterpList.size())
                {
155
                    pdata = vtk::Tools::convertFieldToVTK
156 157 158 159 160 161 162 163
                    (
                        fld.name(),
                        patchInterpList[patchId].faceToPointInterpolate(tpptf)()
                    );
                }
            }
            else
            {
164 165
                coffset +=
                    vtk::Tools::transcribeFloatData(cdata, ptf, coffset);
166 167 168

                if (allowPdata && patchId < patchInterpList.size())
                {
169
                    pdata = vtk::Tools::convertFieldToVTK
170 171 172 173 174
                    (
                        fld.name(),
                        patchInterpList[patchId].faceToPointInterpolate(ptf)()
                    );
                }
175 176
            }
        }
177 178 179 180 181 182 183 184 185

        if (cdata)
        {
            dataset->GetCellData()->AddArray(cdata);
        }
        if (pdata)
        {
            dataset->GetPointData()->AddArray(pdata);
        }
186 187
    }

188 189

    // Face Zones
190 191 192 193 194
    for
    (
        const auto partId
      : rangeFaceZones_.intersection(selectedPartIds_)
    )
195
    {
196 197
        const auto& longName = selectedPartIds_[partId];
        const word zoneName = getFoamName(longName);
198

199
        auto iter = cachedVtp_.find(longName);
200
        if (!iter.found() || !iter.val().dataset)
201
        {
202
            // Should not happen, but for safety require a vtk geometry
203 204
            continue;
        }
205

206
        foamVtpData& vtpData = iter.val();
207
        auto dataset = vtpData.dataset;
208 209 210 211 212 213 214 215 216

        const faceZoneMesh& zMesh = mesh.faceZones();
        const label zoneId = zMesh.findZoneID(zoneName);

        if (zoneId < 0)
        {
            continue;
        }

217 218 219 220 221 222
        vtkSmartPointer<vtkFloatArray> cdata =
            convertFaceFieldToVTK
            (
                fld,
                zMesh[zoneId]
            );
223

224
        dataset->GetCellData()->AddArray(cdata);
225

226
        // TODO: point data
227 228
    }

229 230

    // Face Sets
231 232 233 234 235
    for
    (
        const auto partId
      : rangeFaceSets_.intersection(selectedPartIds_)
    )
236
    {
237 238
        const auto& longName = selectedPartIds_[partId];
        const word selectName = getFoamName(longName);
239

240
        auto iter = cachedVtp_.find(longName);
241
        if (!iter.found() || !iter.val().dataset)
242
        {
243
            // Should not happen, but for safety require a vtk geometry
244 245
            continue;
        }
246
        foamVtpData& vtpData = iter.val();
247
        auto dataset = vtpData.dataset;
248

249
        vtkSmartPointer<vtkFloatArray> cdata = convertFaceFieldToVTK
250 251
        (
            fld,
252
            vtpData.cellMap()
253 254
        );

255
        dataset->GetCellData()->AddArray(cdata);
256

257
        // TODO: point data
258 259 260 261 262 263 264 265 266
    }
}


template<class Type>
void Foam::vtkPVFoam::convertVolFields
(
    const fvMesh& mesh,
    const PtrList<patchInterpolator>& patchInterpList,
267
    const IOobjectList& objects
268 269
)
{
270 271
    typedef GeometricField<Type, fvPatchField, volMesh> FieldType;

272
    forAllConstIters(objects, iter)
273
    {
274
        // Restrict to GeometricField<Type, ...>
275
        const auto& ioobj = *(iter.val());
276

277 278
        if (ioobj.headerClassName() == FieldType::typeName)
        {
279 280 281 282 283 284 285 286 287 288 289 290
            // Throw FatalError, FatalIOError as exceptions
            const bool throwingError = FatalError.throwExceptions();
            const bool throwingIOerr = FatalIOError.throwExceptions();

            try
            {
                // Load field
                FieldType fld(ioobj, mesh);

                // Convert
                convertVolField(patchInterpList, fld);
            }
291
            catch (const Foam::IOerror& ioErr)
292 293
            {
                ioErr.write(Warning, false);
294
                Info<< nl << endl;
295
            }
296
            catch (const Foam::error& err)
297 298 299
            {
                // Bit of trickery to get the original message
                err.write(Warning, false);
300
                Info<< nl << endl;
301
            }
302

303 304 305
            // Restore previous exception throwing state
            FatalError.throwExceptions(throwingError);
            FatalIOError.throwExceptions(throwingIOerr);
306
        }
307 308 309 310 311 312 313 314 315
    }
}


template<class Type>
void Foam::vtkPVFoam::convertDimFields
(
    const fvMesh& mesh,
    const PtrList<patchInterpolator>& patchInterpList,
316
    const IOobjectList& objects
317 318
)
{
319
    typedef DimensionedField<Type, volMesh> FieldType;
320 321
    typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;

322
    forAllConstIters(objects, iter)
323
    {
324
        // Restrict to DimensionedField<Type, ...>
325
        const auto& ioobj = *(iter.val());
326 327

        if (ioobj.headerClassName() != FieldType::typeName)
328 329 330 331
        {
            continue;
        }

332 333 334
        // Throw FatalError, FatalIOError as exceptions
        const bool throwingError = FatalError.throwExceptions();
        const bool throwingIOerr = FatalIOError.throwExceptions();
335

336 337 338 339
        try
        {
            // Load field
            FieldType dimFld(ioobj, mesh);
340

341
            // Construct volField with zero-gradient patch fields
342

343 344 345 346 347 348 349
            IOobject io(dimFld);
            io.readOpt() = IOobject::NO_READ;

            PtrList<fvPatchField<Type>> patchFields(mesh.boundary().size());
            forAll(patchFields, patchI)
            {
                patchFields.set
350
                (
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
                    patchI,
                    fvPatchField<Type>::New
                    (
                        zeroGradientFvPatchField<Type>::typeName,
                        mesh.boundary()[patchI],
                        dimFld
                    )
                );
            }

            VolFieldType volFld
            (
                io,
                dimFld.mesh(),
                dimFld.dimensions(),
                dimFld,
                patchFields
368
            );
369
            volFld.correctBoundaryConditions();
370

371 372
            convertVolField(patchInterpList, volFld);
        }
373
        catch (const Foam::IOerror& ioErr)
374 375
        {
            ioErr.write(Warning, false);
376
            Info<< nl << endl;
377
        }
378
        catch (const Foam::error& err)
379 380 381
        {
            // Bit of trickery to get the original message
            err.write(Warning, false);
382
            Info<< nl << endl;
383
        }
384

385 386 387
        // Restore previous exception throwing state
        FatalError.throwExceptions(throwingError);
        FatalIOError.throwExceptions(throwingIOerr);
388 389 390 391 392 393 394 395 396
    }
}


template<class Type>
void Foam::vtkPVFoam::convertVolFieldBlock
(
    const GeometricField<Type, fvPatchField, volMesh>& fld,
    autoPtr<GeometricField<Type, pointPatchField, pointMesh>>& ptfPtr,
397
    const arrayRange& range
398 399
)
{
400 401 402 403 404
    for
    (
        const auto partId
      : range.intersection(selectedPartIds_)
    )
405
    {
406
        const auto& longName = selectedPartIds_[partId];
407

408
        auto iter = cachedVtu_.find(longName);
409
        if (!iter.found() || !iter.val().dataset)
410
        {
411
            // Should not happen, but for safety require a vtk geometry
412 413
            continue;
        }
414

415
        foamVtuData& vtuData = iter.val();
416
        auto dataset = vtuData.dataset;
417

418
        vtkSmartPointer<vtkFloatArray> cdata = convertVolFieldToVTK
419 420
        (
            fld,
421
            vtuData
422
        );
423
        dataset->GetCellData()->AddArray(cdata);
424 425 426

        if (ptfPtr.valid())
        {
427 428 429 430 431 432 433
            vtkSmartPointer<vtkFloatArray> pdata = convertPointField
            (
                ptfPtr(),
                fld,
                vtuData
            );
            dataset->GetPointData()->AddArray(pdata);
434 435 436 437 438
        }
    }
}


439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//
// area-fields
//

template<class Type>
void Foam::vtkPVFoam::convertAreaFields
(
    const faMesh& mesh,
    const IOobjectList& objects
)
{
    typedef GeometricField<Type, faPatchField, areaMesh> FieldType;

    const List<label> partIds =
        rangeArea_.intersection(selectedPartIds_);

    if (partIds.empty())
    {
        return;
    }

    forAllConstIters(objects, iter)
    {
        // Restrict to GeometricField<Type, ...>
464
        const auto& ioobj = *(iter.val());
465 466 467

        if (ioobj.headerClassName() == FieldType::typeName)
        {
468 469 470
            // Throw FatalError, FatalIOError as exceptions
            const bool throwingError = FatalError.throwExceptions();
            const bool throwingIOerr = FatalIOError.throwExceptions();
471

472
            try
473
            {
474 475
                // Load field
                FieldType fld(ioobj, mesh);
476

477 478
                // Convert
                for (const auto partId : partIds)
479
                {
480
                    const auto& longName = selectedPartIds_[partId];
481

482
                    auto iter = cachedVtp_.find(longName);
483
                    if (!iter.found() || !iter.val().dataset)
484 485 486 487 488
                    {
                        // Should not happen, but for safety require a vtk
                        // geometry
                        continue;
                    }
489

490
                    foamVtpData& vtpData = iter.val();
491 492
                    auto dataset = vtpData.dataset;

493 494 495 496 497 498 499
                    vtkSmartPointer<vtkFloatArray> cdata =
                        vtk::Tools::convertFieldToVTK
                        (
                            fld.name(),
                            fld
                        );

500 501 502
                    dataset->GetCellData()->AddArray(cdata);
                }
            }
503
            catch (const Foam::IOerror& ioErr)
504 505
            {
                ioErr.write(Warning, false);
506
                Info<< nl << endl;
507
            }
508
            catch (const Foam::error& err)
509 510 511
            {
                // Bit of trickery to get the original message
                err.write(Warning, false);
512
                Info<< nl << endl;
513
            }
514 515 516 517

            // Restore previous exception throwing state
            FatalError.throwExceptions(throwingError);
            FatalIOError.throwExceptions(throwingIOerr);
518 519 520 521 522
        }
    }
}


523
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
524

525 526 527 528 529 530 531
//
// point-fields
//
template<class Type>
void Foam::vtkPVFoam::convertPointFields
(
    const pointMesh& pMesh,
532
    const IOobjectList& objects
533 534 535
)
{
    const polyMesh& mesh = pMesh.mesh();
536 537

    typedef GeometricField<Type, pointPatchField, pointMesh> FieldType;
538

539
    forAllConstIters(objects, iter)
540
    {
541
        // Restrict to this GeometricField<Type, ...>
542
        const auto& ioobj = *(iter.val());
543 544 545

        const word& fieldName = ioobj.name();
        if (ioobj.headerClassName() != FieldType::typeName)
546 547 548 549
        {
            continue;
        }

550 551
        DebugInfo
            << "convertPointFields : " << fieldName << nl;
552

553 554 555
        // Throw FatalError, FatalIOError as exceptions
        const bool throwingError = FatalError.throwExceptions();
        const bool throwingIOerr = FatalIOError.throwExceptions();
556

557
        try
558
        {
559
            FieldType pfld(ioobj, pMesh);
560

561 562 563 564 565 566 567 568 569 570
            convertPointFieldBlock(pfld, rangeVolume_);     // internalMesh
            convertPointFieldBlock(pfld, rangeCellZones_);  // cellZones
            convertPointFieldBlock(pfld, rangeCellSets_);   // cellSets

            // Patches - currently skip field conversion for groups
            for
            (
                const auto partId
              : rangePatches_.intersection(selectedPartIds_)
            )
571
            {
572
                const auto& longName = selectedPartIds_[partId];
573

574
                auto iter = cachedVtp_.find(longName);
575
                if (!iter.found() || !iter.val().dataset)
576 577 578 579
                {
                    // Should not happen, but for safety require a vtk geometry
                    continue;
                }
580

581
                foamVtpData& vtpData = iter.val();
582
                auto dataset = vtpData.dataset;
583

584
                const labelUList& patchIds = vtpData.additionalIds();
585 586 587 588
                if (patchIds.size() != 1)
                {
                    continue;
                }
589

590
                const label patchId = patchIds[0];
591

592 593 594 595 596 597
                vtkSmartPointer<vtkFloatArray> pdata =
                    vtk::Tools::convertFieldToVTK
                    (
                        fieldName,
                        pfld.boundaryField()[patchId].patchInternalField()()
                    );
598

599 600
                dataset->GetPointData()->AddArray(pdata);
            }
601

602 603 604 605 606 607
            // Face Zones
            for
            (
                const auto partId
              : rangeFaceZones_.intersection(selectedPartIds_)
            )
608
            {
609 610
                const auto& longName = selectedPartIds_[partId];
                const word zoneName = getFoamName(longName);
611

612
                auto iter = cachedVtp_.find(longName);
613
                if (!iter.found() || !iter.val().dataset)
614 615 616 617
                {
                    // Should not happen, but for safety require a vtk geometry
                    continue;
                }
618

619
                foamVtpData& vtpData = iter.val();
620
                auto dataset = vtpData.dataset;
621

622
                const label zoneId = mesh.faceZones().findZoneID(zoneName);
623

624 625 626 627
                if (zoneId < 0)
                {
                    continue;
                }
628

629 630
                // Extract the field on the zone
                Field<Type> znfld
631
                (
632 633
                    pfld.primitiveField(),
                    mesh.faceZones()[zoneId]().meshPoints()
634 635
                );

636
                vtkSmartPointer<vtkFloatArray> pdata =
637
                    vtk::Tools::convertFieldToVTK
638 639 640 641 642 643 644 645
                    (
                        fieldName,
                        znfld
                    );

                dataset->GetPointData()->AddArray(pdata);
            }
        }
646
        catch (const Foam::IOerror& ioErr)
647 648
        {
            ioErr.write(Warning, false);
649
            Info<< nl << endl;
650
        }
651
        catch (const Foam::error& err)
652 653 654
        {
            // Bit of trickery to get the original message
            err.write(Warning, false);
655
            Info<< nl << endl;
656 657 658 659 660
        }

        // Restore previous exception throwing state
        FatalError.throwExceptions(throwingError);
        FatalIOError.throwExceptions(throwingIOerr);
661 662 663 664 665 666 667 668
    }
}


template<class Type>
void Foam::vtkPVFoam::convertPointFieldBlock
(
    const GeometricField<Type, pointPatchField, pointMesh>& pfld,
669
    const arrayRange& range
670 671
)
{
672 673 674 675 676
    for
    (
        const auto partId
      : range.intersection(selectedPartIds_)
    )
677
    {
678
        const auto& longName = selectedPartIds_[partId];
679

680
        auto iter = cachedVtu_.find(longName);
681
        if (!iter.found() || !iter.val().dataset)
682
        {
683
            // Should not happen, but for safety require a vtk geometry
684
            continue;
685
        }
686

687
        foamVtuData& vtuData = iter.val();
688
        auto dataset = vtuData.dataset;
689

690
        vtkSmartPointer<vtkFloatArray> pdata = convertPointField
691 692 693 694 695
        (
            pfld,
            GeometricField<Type, fvPatchField, volMesh>::null(),
            vtuData
        );
696 697

        dataset->GetPointData()->AddArray(pdata);
698
    }
699 700 701 702
}


template<class Type>
703
vtkSmartPointer<vtkFloatArray> Foam::vtkPVFoam::convertPointField
704 705 706
(
    const GeometricField<Type, pointPatchField, pointMesh>& pfld,
    const GeometricField<Type, fvPatchField, volMesh>& vfld,
707
    const foamVtuData& vtuData
708 709
)
{
710 711
    const labelUList& addPointCellLabels = vtuData.additionalIds();
    const labelUList& pointMap = vtuData.pointMap();
712

713
    // Use a pointMap or address directly into mesh
714 715
    const label nPoints = (pointMap.size() ? pointMap.size() : pfld.size());

716
    auto data = vtkSmartPointer<vtkFloatArray>::New();
717
    data->SetNumberOfComponents(static_cast<int>(pTraits<Type>::nComponents));
718
    data->SetNumberOfTuples(nPoints + addPointCellLabels.size());
719 720 721 722

    // Note: using the name of the original volField
    // not the name generated by the interpolation "volPointInterpolate(<name>)"

723
    if (notNull(vfld))
724
    {
725
        data->SetName(vfld.name().c_str());
726 727 728
    }
    else
    {
729
        data->SetName(pfld.name().c_str());
730 731
    }

732 733 734 735 736 737
    DebugInfo
        << "Convert point field: " << pfld.name()
        << " size="  << (nPoints + addPointCellLabels.size())
        << " (" << nPoints << " + " << addPointCellLabels.size()
        << ") nComp=" << static_cast<int>(pTraits<Type>::nComponents) << nl;

738

739
    float scratch[pTraits<Type>::nComponents];
740

741
    vtkIdType pointi = 0;
742 743
    if (pointMap.size())
    {
744
        for (const label meshPointi : pointMap)
745
        {
746 747
            vtk::Tools::foamToVtkTuple(scratch, pfld[meshPointi]);
            data->SetTuple(pointi++, scratch);
748 749 750 751
        }
    }
    else
    {
752
        for (const Type& val : pfld)
753
        {
754 755
            vtk::Tools::foamToVtkTuple(scratch, val);
            data->SetTuple(pointi++, scratch);
756 757 758
        }
    }

759
    // Continue with additional points
760
    // - correspond to cell centres
761

762
    if (notNull(vfld))
763
    {
764
        for (const label meshCelli : addPointCellLabels)
765
        {
766 767
            vtk::Tools::foamToVtkTuple(scratch, vfld[meshCelli]);
            data->SetTuple(pointi++, scratch);
768 769 770 771
        }
    }
    else
    {
772
        for (const label meshCelli : addPointCellLabels)
773
        {
774 775 776 777 778 779
            vtk::Tools::foamToVtkTuple
            (
                scratch,
                interpolatePointToCell(pfld, meshCelli)
            );
            data->SetTuple(pointi++, scratch);
780 781 782
        }
    }

783
    return data;
784 785 786 787 788 789 790 791 792 793 794 795
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//
// lagrangian-fields
//

template<class Type>
void Foam::vtkPVFoam::convertLagrangianFields
(
    const IOobjectList& objects,
796
    vtkPolyData* vtkmesh
797 798
)
{
799
    forAllConstIters(objects, iter)
800
    {
801
        // Restrict to IOField<Type>
802
        const auto& ioobj = *(iter.val());
803 804

        if (ioobj.headerClassName() == IOField<Type>::typeName)
805
        {
806 807 808
            // Throw FatalError, FatalIOError as exceptions
            const bool throwingError = FatalError.throwExceptions();
            const bool throwingIOerr = FatalIOError.throwExceptions();
809

810 811 812 813 814
            try
            {
                IOField<Type> fld(ioobj);

                vtkSmartPointer<vtkFloatArray> data =
815
                    vtk::Tools::convertFieldToVTK
816 817 818 819 820 821 822 823 824
                    (
                        ioobj.name(),
                        fld
                    );

                // Provide identical data as cell and as point data
                vtkmesh->GetCellData()->AddArray(data);
                vtkmesh->GetPointData()->AddArray(data);
            }
825
            catch (const Foam::IOerror& ioErr)
826 827
            {
                ioErr.write(Warning, false);
828
                Info<< nl << endl;
829
            }
830
            catch (const Foam::error& err)
831 832 833
            {
                // Bit of trickery to get the original message
                err.write(Warning, false);
834
                Info<< nl << endl;
835
            }
836

837 838 839
            // Restore previous exception throwing state
            FatalError.throwExceptions(throwingError);
            FatalIOError.throwExceptions(throwingIOerr);
840 841 842 843 844 845 846 847 848 849 850
        }
    }
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//
// low-level conversions
//

template<class Type>
851 852
vtkSmartPointer<vtkFloatArray>
Foam::vtkPVFoam::convertFaceFieldToVTK
853 854 855
(
    const GeometricField<Type, fvPatchField, volMesh>& fld,
    const labelUList& faceLabels
856
) const
857