libMesh
Loading...
Searching...
No Matches
trilinos_epetra_vector.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#ifndef LIBMESH_TRILINOS_EPETRA_VECTOR_H
19#define LIBMESH_TRILINOS_EPETRA_VECTOR_H
20
21
22#include "libmesh/libmesh_common.h"
23
24#ifdef LIBMESH_TRILINOS_HAVE_EPETRA
25
26// Local includes
27#include "libmesh/numeric_vector.h"
28#include "libmesh/parallel.h"
29
30// Trilinos includes
31#include "libmesh/ignore_warnings.h"
32#include <Epetra_CombineMode.h>
33#include <Epetra_Map.h>
34#include <Epetra_MultiVector.h>
35#include <Epetra_Vector.h>
36#include <Epetra_MpiComm.h>
37#include "libmesh/restore_warnings.h"
38
39// C++ includes
40#include <cstddef>
41#include <limits>
42#include <memory>
43#include <mutex>
44#include <vector>
45
46// Forward declarations
47class Epetra_IntSerialDenseVector;
48class Epetra_SerialDenseVector;
49
50namespace libMesh
51{
52
53// forward declarations
54template <typename T> class SparseMatrix;
55
64template <typename T>
65class EpetraVector final : public NumericVector<T>
66{
67public:
68
72 explicit
75
79 explicit
81 const numeric_index_type n,
83
89 const numeric_index_type n,
90 const numeric_index_type n_local,
92
99 const numeric_index_type N,
100 const numeric_index_type n_local,
101 const std::vector<numeric_index_type> & ghost,
102 const ParallelType type = AUTOMATIC);
103
111 EpetraVector(Epetra_Vector & v,
113
120 EpetraVector (const EpetraVector &) = delete;
123 virtual ~EpetraVector ();
124
125 virtual void close () override;
126
130 virtual void clear () noexcept override;
131
132 virtual void zero () override;
133
134 virtual std::unique_ptr<NumericVector<T>> zero_clone () const override;
135
136 virtual std::unique_ptr<NumericVector<T>> clone () const override;
137
138 virtual void init (const numeric_index_type N,
139 const numeric_index_type n_local,
140 const bool fast=false,
141 const ParallelType type=AUTOMATIC) override;
142
143 virtual void init (const numeric_index_type N,
144 const bool fast=false,
145 const ParallelType type=AUTOMATIC) override;
146
147 virtual void init (const numeric_index_type N,
148 const numeric_index_type n_local,
149 const std::vector<numeric_index_type> & ghost,
150 const bool fast = false,
151 const ParallelType = AUTOMATIC) override;
152
153 virtual void init (const NumericVector<T> & other,
154 const bool fast = false) override;
155
156 virtual NumericVector<T> & operator= (const T s) override;
157
158 virtual NumericVector<T> & operator= (const NumericVector<T> & v) override;
159
160 virtual NumericVector<T> & operator= (const std::vector<T> & v) override;
161
162 virtual Real min () const override;
163
164 virtual Real max () const override;
165
166 virtual T sum () const override;
167
168 virtual Real l1_norm () const override;
169
170 virtual Real l2_norm () const override;
171
172 virtual Real linfty_norm () const override;
173
174 virtual numeric_index_type size () const override;
175
176 virtual numeric_index_type local_size() const override;
177
178 virtual numeric_index_type first_local_index() const override;
179
180 virtual numeric_index_type last_local_index() const override;
181
182 virtual T operator() (const numeric_index_type i) const override;
183
184 virtual NumericVector<T> & operator += (const NumericVector<T> & v) override;
185
186 virtual NumericVector<T> & operator -= (const NumericVector<T> & v) override;
187
188 virtual NumericVector<T> & operator *= (const NumericVector<T> & v) override;
189
190 virtual NumericVector<T> & operator /= (const NumericVector<T> & v) override;
191
192 virtual void reciprocal() override;
193
194 virtual void conjugate() override;
195
196 virtual void set (const numeric_index_type i, const T value) override;
197
198 virtual void add (const numeric_index_type i, const T value) override;
199
200 virtual void add (const T s) override;
201
202 virtual void add (const NumericVector<T> & v) override;
203
204 virtual void add (const T a, const NumericVector<T> & v) override;
205
210 using NumericVector<T>::add_vector;
211
212 virtual void add_vector (const T * v,
213 const std::vector<numeric_index_type> & dof_indices) override;
214
215 virtual void add_vector (const NumericVector<T> & v,
216 const SparseMatrix<T> & A) override;
217
218 virtual void add_vector_transpose (const NumericVector<T> & v,
219 const SparseMatrix<T> & A) override;
220
225 using NumericVector<T>::insert;
226
227 virtual void insert (const T * v,
228 const std::vector<numeric_index_type> & dof_indices) override;
229
230 virtual void scale (const T factor) override;
231
232 virtual void abs() override;
233
234 virtual T dot(const NumericVector<T> & v) const override;
235
236 virtual void localize (std::vector<T> & v_local) const override;
237
238 virtual void localize (NumericVector<T> & v_local) const override;
239
240 virtual void localize (NumericVector<T> & v_local,
241 const std::vector<numeric_index_type> & send_list) const override;
242
243 virtual void localize (std::vector<T> & v_local,
244 const std::vector<numeric_index_type> & indices) const override;
245
246 virtual void localize (const numeric_index_type first_local_idx,
247 const numeric_index_type last_local_idx,
248 const std::vector<numeric_index_type> & send_list) override;
249
250 virtual void localize_to_one (std::vector<T> & v_local,
251 const processor_id_type proc_id=0) const override;
252
253 virtual void pointwise_mult (const NumericVector<T> & vec1,
254 const NumericVector<T> & vec2) override;
255
256 virtual void swap (NumericVector<T> & v) override;
257
258 virtual std::size_t max_allowed_id() const override;
259
268 Epetra_Vector * vec () { libmesh_assert(_vec); return _vec; }
269
270private:
271
275 Epetra_Vector * _vec;
276
280 std::unique_ptr<Epetra_Map> _map;
281
287
288 // The following were copied (and slightly modified) from
289 // Epetra_FEVector.h in order to allow us to use a standard
290 // Epetra_Vector... which is more compatible with other Trilinos
291 // packages such as NOX. All of this code is originally under LGPL
292
297 int SumIntoGlobalValues(int numIDs,
298 const int * GIDs,
299 const double * values);
300
311 int SumIntoGlobalValues(const Epetra_IntSerialDenseVector & GIDs,
312 const Epetra_SerialDenseVector & values);
313
318 int ReplaceGlobalValues(int numIDs,
319 const int * GIDs,
320 const double * values);
321
332 int ReplaceGlobalValues(const Epetra_IntSerialDenseVector & GIDs,
333 const Epetra_SerialDenseVector & values);
334
335 int SumIntoGlobalValues(int numIDs,
336 const int * GIDs,
337 const int * numValuesPerID,
338 const double * values);
339
340 int ReplaceGlobalValues(int numIDs,
341 const int * GIDs,
342 const int * numValuesPerID,
343 const double * values);
344
353 int GlobalAssemble(Epetra_CombineMode mode = Add);
354
359 {
361 }
362
363 void FEoperatorequals(const EpetraVector & source);
364
365 int inputValues(int numIDs,
366 const int * GIDs,
367 const double * values,
368 bool accumulate);
369
370 int inputValues(int numIDs,
371 const int * GIDs,
372 const int * numValuesPerID,
373 const double * values,
374 bool accumulate);
375
376 int inputNonlocalValue(int GID,
377 double value,
378 bool accumulate);
379
380 int inputNonlocalValues(int GID,
381 int numValues,
382 const double * values,
383 bool accumulate);
384
385 void destroyNonlocalData();
386
389 double * myCoefs_;
390
395 double ** nonlocalCoefs_;
396
402 unsigned char last_edit;
403
405};
406
407
408/*----------------------- Inline functions ----------------------------------*/
409
410
411
412template <typename T>
413inline
415 const ParallelType type) :
416 NumericVector<T>(comm, type),
417 _destroy_vec_on_exit(true),
418 myFirstID_(0),
419 myNumIDs_(0),
420 myCoefs_(nullptr),
421 nonlocalIDs_(nullptr),
422 nonlocalElementSize_(nullptr),
423 numNonlocalIDs_(0),
424 allocatedNonlocalLength_(0),
425 nonlocalCoefs_(nullptr),
426 last_edit(0),
427 ignoreNonLocalEntries_(false)
428{
429 this->_type = type;
430}
431
432
433
434template <typename T>
435inline
437 const numeric_index_type n,
438 const ParallelType type) :
439 NumericVector<T>(comm, type),
440 _destroy_vec_on_exit(true),
441 myFirstID_(0),
442 myNumIDs_(0),
443 myCoefs_(nullptr),
444 nonlocalIDs_(nullptr),
445 nonlocalElementSize_(nullptr),
446 numNonlocalIDs_(0),
447 allocatedNonlocalLength_(0),
448 nonlocalCoefs_(nullptr),
449 last_edit(0),
450 ignoreNonLocalEntries_(false)
451
452{
453 this->init(n, n, false, type);
454}
455
456
457
458template <typename T>
459inline
461 const numeric_index_type n,
462 const numeric_index_type n_local,
463 const ParallelType type) :
464 NumericVector<T>(comm, type),
465 _destroy_vec_on_exit(true),
466 myFirstID_(0),
467 myNumIDs_(0),
468 myCoefs_(nullptr),
469 nonlocalIDs_(nullptr),
470 nonlocalElementSize_(nullptr),
471 numNonlocalIDs_(0),
472 allocatedNonlocalLength_(0),
473 nonlocalCoefs_(nullptr),
474 last_edit(0),
475 ignoreNonLocalEntries_(false)
476{
477 this->init(n, n_local, false, type);
478}
479
480
481
482
483template <typename T>
484inline
486 const Parallel::Communicator & comm) :
487 NumericVector<T>(comm, AUTOMATIC),
488 _destroy_vec_on_exit(false),
489 myFirstID_(0),
490 myNumIDs_(0),
491 myCoefs_(nullptr),
492 nonlocalIDs_(nullptr),
493 nonlocalElementSize_(nullptr),
494 numNonlocalIDs_(0),
495 allocatedNonlocalLength_(0),
496 nonlocalCoefs_(nullptr),
497 last_edit(0),
498 ignoreNonLocalEntries_(false)
499{
500 _vec = &v;
501
502 this->_type = PARALLEL; // FIXME - need to determine this from v!
503
504 myFirstID_ = _vec->Map().MinMyGID();
505 myNumIDs_ = _vec->Map().NumMyElements();
506
507 _map = std::make_unique<Epetra_Map>
508 (_vec->GlobalLength(),
509 _vec->MyLength(),
510 0, // IndexBase = 0 for C/C++, 1 for Fortran.
511 Epetra_MpiComm (this->comm().get()));
512
513 //Currently we impose the restriction that NumVectors==1, so we won't
514 //need the LDA argument when calling ExtractView. Hence the "dummy" arg.
515 int dummy;
516 _vec->ExtractView(&myCoefs_, &dummy);
517
518 this->_is_closed = true;
519 this->_is_initialized = true;
520}
521
522
523
524template <typename T>
525inline
527 const numeric_index_type n,
528 const numeric_index_type n_local,
529 const std::vector<numeric_index_type> & ghost,
530 const ParallelType type) :
531 NumericVector<T>(comm, AUTOMATIC),
532 _destroy_vec_on_exit(true),
533 myFirstID_(0),
534 myNumIDs_(0),
535 myCoefs_(nullptr),
536 nonlocalIDs_(nullptr),
537 nonlocalElementSize_(nullptr),
538 numNonlocalIDs_(0),
539 allocatedNonlocalLength_(0),
540 nonlocalCoefs_(nullptr),
541 last_edit(0),
542 ignoreNonLocalEntries_(false)
543{
544 this->init(n, n_local, ghost, false, type);
545}
546
547
548
549// Default implementation for solver packages for which ghosted
550// vectors are not yet implemented.
551template <class T>
553 const bool fast)
554{
555 this->init(other.size(),other.local_size(),fast,other.type());
556}
557
558
559
560template <typename T>
561inline
563{
564 this->clear ();
565}
566
567
568
569template <typename T>
570inline
572 const numeric_index_type n_local,
573 const bool fast,
574 const ParallelType type)
575{
576 // We default to allocating n_local local storage
577 numeric_index_type my_n_local = n_local;
578
579 if (type == AUTOMATIC)
580 {
581 if (n == n_local)
582 this->_type = SERIAL;
583 else
584 this->_type = PARALLEL;
585 }
586 else if (type == GHOSTED)
587 {
588 // We don't yet support GHOSTED Epetra vectors, so to get the
589 // same functionality we need a SERIAL vector with local
590 // storage allocated for every entry.
591 this->_type = SERIAL;
592 my_n_local = n;
593 }
594 else
595 this->_type = type;
596
597 libmesh_assert ((this->_type==SERIAL && n==my_n_local) ||
598 this->_type==PARALLEL);
599
600 _map = std::make_unique<Epetra_Map>
601 (static_cast<int>(n),
602 my_n_local,
603 0,
604 Epetra_MpiComm (this->comm().get()));
605
606 _vec = new Epetra_Vector(*_map);
607
608 myFirstID_ = _vec->Map().MinMyGID();
609 myNumIDs_ = _vec->Map().NumMyElements();
610
611 // Currently we impose the restriction that NumVectors==1, so we won't
612 // need the LDA argument when calling ExtractView. Hence the "dummy" arg.
613 int dummy;
614 _vec->ExtractView(&myCoefs_, &dummy);
615
616 this->_is_initialized = true;
617 this->_is_closed = true;
618 this->last_edit = 0;
619
620 if (fast == false)
621 this->zero ();
622}
623
624
625template <typename T>
626inline
628 const numeric_index_type n_local,
629 const std::vector<numeric_index_type> & /*ghost*/,
630 const bool fast,
631 const ParallelType type)
632{
633 // TODO: we shouldn't ignore the ghost sparsity pattern
634 this->init(n, n_local, fast, type);
635}
636
637
638
639template <typename T>
640inline
642 const bool fast,
643 const ParallelType type)
644{
645 this->init(n,n,fast,type);
646}
647
648
649
650template <typename T>
651inline
653{
654 libmesh_assert (this->initialized());
655
656 // Are we adding or inserting?
657 unsigned char global_last_edit = last_edit;
658 this->comm().max(global_last_edit);
659 libmesh_assert(!last_edit || last_edit == global_last_edit);
660
661 if (global_last_edit == 1)
662 this->GlobalAssemble(Insert);
663 else if (global_last_edit == 2)
664 this->GlobalAssemble(Add);
665 else
666 libmesh_assert(!global_last_edit);
667
668 this->_is_closed = true;
669 this->last_edit = 0;
670}
671
672
673
674template <typename T>
675inline
677{
678 if (this->initialized())
679 {
680 // We might just be an interface to a user-provided _vec
681 if (this->_destroy_vec_on_exit)
682 {
683 delete _vec;
684 _vec = nullptr;
685 }
686
687 // But we currently always own our own _map
688 _map.reset();
689 }
690
691 this->_is_closed = this->_is_initialized = false;
692}
693
694
695
696template <typename T>
697inline
699{
700 libmesh_assert (this->initialized());
701 libmesh_assert (this->closed());
702
703 _vec->PutScalar(0.0);
704}
705
706
707
708template <typename T>
709inline
710std::unique_ptr<NumericVector<T>> EpetraVector<T>::zero_clone () const
711{
712 std::unique_ptr<NumericVector<T>> cloned_vector =
713 std::make_unique<EpetraVector<T>>(this->comm(), AUTOMATIC);
714 cloned_vector->init(*this);
715 return cloned_vector;
716}
717
718
719
720template <typename T>
721inline
722std::unique_ptr<NumericVector<T>> EpetraVector<T>::clone () const
723{
724 std::unique_ptr<NumericVector<T>> cloned_vector =
725 std::make_unique<EpetraVector<T>>(this->comm(), AUTOMATIC);
726 cloned_vector->init(*this, true);
727 *cloned_vector = *this;
728 return cloned_vector;
729}
730
731
732
733template <typename T>
734inline
736{
737 libmesh_assert (this->initialized());
738
739 return _vec->GlobalLength();
740}
741
742
743
744template <typename T>
745inline
747{
748 libmesh_assert (this->initialized());
749
750 return _vec->MyLength();
751}
752
753template <typename T>
754inline
756{
757 libmesh_assert (this->initialized());
758
759 return _vec->Map().MinMyGID();
760}
761
762
763
764template <typename T>
765inline
767{
768 libmesh_assert (this->initialized());
769
770 return _vec->Map().MaxMyGID()+1;
771}
772
773
774template <typename T>
775inline
777{
778 libmesh_assert (this->initialized());
779 libmesh_assert ( ((i >= this->first_local_index()) &&
780 (i < this->last_local_index())) );
781
782 return (*_vec)[i-this->first_local_index()];
783}
784
785
786
787template <typename T>
788inline
790{
791 libmesh_assert (this->initialized());
792
793 T value;
794
795 _vec->MinValue(&value);
796
797 return value;
798}
799
800
801
802template <typename T>
803inline
805{
806 libmesh_assert (this->initialized());
807
808 T value;
809
810 _vec->MaxValue(&value);
811
812 return value;
813}
814
815
816
817template <typename T>
818inline
820{
822
823 EpetraVector<T> & v = cast_ref<EpetraVector<T> &>(other);
824
825 std::swap(_vec, v._vec);
826 _map.swap(v._map);
827 std::swap(_destroy_vec_on_exit, v._destroy_vec_on_exit);
828 std::swap(myFirstID_, v.myFirstID_);
829 std::swap(myNumIDs_, v.myNumIDs_);
830 std::swap(myCoefs_, v.myCoefs_);
831 std::swap(nonlocalIDs_, v.nonlocalIDs_);
832 std::swap(nonlocalElementSize_, v.nonlocalElementSize_);
833 std::swap(numNonlocalIDs_, v.numNonlocalIDs_);
834 std::swap(allocatedNonlocalLength_, v.allocatedNonlocalLength_);
835 std::swap(nonlocalCoefs_, v.nonlocalCoefs_);
836 std::swap(last_edit, v.last_edit);
837 std::swap(ignoreNonLocalEntries_, v.ignoreNonLocalEntries_);
838}
839
840
841
842template <typename T>
843inline
845{
846 // Epetra_Vector seems to use hard-coded ints in its various indexing routines.
847 return std::numeric_limits<int>::max();
848}
849
850
851
852// Trilinos only got serious about const in version 10.4
853inline
855{
856 return reinterpret_cast<int *>(const_cast<numeric_index_type *>(p));
857}
858
859} // namespace libMesh
860
861
862#endif // #ifdef LIBMESH_TRILINOS_HAVE_EPETRA
863#endif // LIBMESH_TRILINOS_EPETRA_VECTOR_H
This class provides a nice interface to the Trilinos Epetra_Vector object.
EpetraVector(const Parallel::Communicator &comm, const ParallelType type=AUTOMATIC)
Dummy-Constructor.
int SumIntoGlobalValues(int numIDs, const int *GIDs, const double *values)
Accumulate values into the vector, adding them to any values that already exist for the specified ind...
virtual void localize_to_one(std::vector< T > &v_local, const processor_id_type proc_id=0) const override
Creates a local copy of the global vector in v_local only on processor proc_id.
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices) override
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
virtual Real min() const override
virtual void swap(NumericVector< T > &v) override
Swaps the contents of this with v.
virtual std::unique_ptr< NumericVector< T > > zero_clone() const override
int ReplaceGlobalValues(int numIDs, const int *GIDs, const double *values)
Copy values into the vector overwriting any values that already exist for the specified indices.
virtual void abs() override
Sets for each entry in the vector.
virtual numeric_index_type local_size() const override
void FEoperatorequals(const EpetraVector &source)
EpetraVector(EpetraVector &&)=delete
This class manages the lifetime of an Epetra_Vector manually, so we don't want to allow any automatic...
virtual numeric_index_type last_local_index() const override
unsigned char last_edit
Keep track of whether the last write operation on this vector was nothing (0) or a sum (1) or an add ...
int inputNonlocalValue(int GID, double value, bool accumulate)
int inputNonlocalValues(int GID, int numValues, const double *values, bool accumulate)
virtual void add_vector_transpose(const NumericVector< T > &v, const SparseMatrix< T > &A) override
Computes , i.e.
virtual void add(const numeric_index_type i, const T value) override
Adds value to the vector entry specified by i.
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices) override
Inserts the entries of v in *this at the locations specified by v.
virtual void clear() noexcept override
clear() is called from the destructor, so it should not throw.
virtual std::unique_ptr< NumericVector< T > > clone() const override
virtual numeric_index_type size() const override
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual void set(const numeric_index_type i, const T value) override
Sets v(i) = value.
EpetraVector & operator=(const EpetraVector &)=delete
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
Computes (summation not implied) i.e.
virtual T sum() const override
virtual std::size_t max_allowed_id() const override
int inputValues(int numIDs, const int *GIDs, const double *values, bool accumulate)
virtual Real max() const override
void setIgnoreNonLocalEntries(bool flag)
Set whether or not non-local data values should be ignored.
virtual void init(const numeric_index_type N, const numeric_index_type n_local, const bool fast=false, const ParallelType type=AUTOMATIC) override
Change the dimension of the vector to n.
virtual Real l1_norm() const override
virtual void reciprocal() override
Computes the component-wise reciprocal, .
std::unique_ptr< Epetra_Map > _map
Holds the distributed Map.
virtual T dot(const NumericVector< T > &v) const override
virtual void conjugate() override
Negates the imaginary component of each entry in the vector.
virtual T operator()(const numeric_index_type i) const override
virtual Real linfty_norm() const override
bool _destroy_vec_on_exit
This boolean value should only be set to false for the constructor which takes a Epetra Vec object.
EpetraVector(const EpetraVector &)=delete
virtual void localize(std::vector< T > &v_local) const override
Creates a copy of the global vector in the local vector v_local.
int GlobalAssemble(Epetra_CombineMode mode=Add)
Gather any overlapping/shared data into the non-overlapping partitioning defined by the Map that was ...
virtual void scale(const T factor) override
Scale each element of the vector by the given factor.
virtual numeric_index_type first_local_index() const override
virtual Real l2_norm() const override
virtual void zero() override
Set all entries to zero.
Epetra_Vector * _vec
Actual Epetra vector datatype to hold vector entries.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void get(const std::vector< numeric_index_type > &index, T *values) const
Access multiple components at once.
ParallelType type() const
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
ParallelType _type
Type of vector.
bool _is_initialized
true once init() has been called.
virtual numeric_index_type size() const =0
bool _is_closed
Flag which tracks whether the vector's values are consistent on all processors after insertion or add...
virtual numeric_index_type local_size() const =0
const Parallel::Communicator & comm() const
Generic sparse matrix.
The libMesh namespace provides an interface to certain functionality in the library.
ParallelType
Defines an enum for parallel data structure types.
bool closed()
Checks that the library has been closed.
Definition libmesh.C:331
libmesh_assert(ctx)
const Number zero
.
Definition libmesh.h:297
dof_id_type numeric_index_type
Definition id_types.h:99
bool initialized()
Checks that library initialization has been done.
Definition libmesh.C:324
int * numeric_trilinos_cast(const numeric_index_type *p)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
static const bool value
Definition xdr_io.C:55