globalMeshData.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Class
25  Foam::globalMeshData
26 
27 Description
28  Various mesh related information for a parallel run. Upon construction,
29  constructs all info using parallel communication.
30 
31  Requires:
32  - all processor patches to have correct ordering.
33  - all processorPatches to have their transforms set.
34 
35  The shared point and edge addressing calculates addressing for points
36  and edges on coupled patches. In the 'old' way a distinction was made
37  between points/edges that are only on two processors and those that are
38  on multiple processors. The problem is that those on multiple processors
39  do not allow any transformations and require a global reduction on the
40  master processor.
41 
42  The alternative is to have an exchange schedule
43  (through a 'distributionMap')
44  which sends all point/edge data (no distinction is made between
45  those on two and those on more than two coupled patches) to the local
46  'master'. This master then does any calculation and sends
47  the result back to the 'slave' points/edges. This only needs to be done
48  on points on coupled faces. Any transformation is done using a
49  predetermined set of transformations - since transformations have to be
50  space filling only a certain number of transformation is supported.
51 
52  The exchange needs
53  - a field of data
54  - a distributionMap which does all parallel exchange and transformations
55  This appends remote data to the end of the field.
56  - a set of indices which indicate where to get untransformed data in the
57  field
58  - a set of indices which indicate where to get transformed data in the
59  field
60 
61  Note:
62  - compared to 17x nTotalFaces, nTotalPoints do not compensate for
63  shared points since this would trigger full connectivity analysis
64  - most calculation is demand driven and uses parallel communication
65  so make sure to invoke on all processors at the same time
66  - old sharedEdge calculation: currently an edge is considered shared if it
67  uses two shared points and is used more than once. This is not correct
68  on processor patches but it only slightly overestimates the number of
69  shared edges. Doing full analysis of how many patches use the edge
70  would be too complicated
71 
72 See also
73  distributionMap
74  globalIndexAndTransform
75 
76 SourceFiles
77  globalMeshData.C
78  globalMeshDataTemplates.C
79 
80 \*---------------------------------------------------------------------------*/
81 
82 #ifndef globalMeshData_H
83 #define globalMeshData_H
84 
85 #include "processorTopology.H"
86 #include "labelPair.H"
87 #include "indirectPrimitivePatch.H"
88 
89 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
90 
91 namespace Foam
92 {
93 
94 // Forward declaration of friend functions and operators
95 
96 class polyMesh;
97 class distributionMap;
98 template<class T> class EdgeMap;
99 class globalIndex;
100 class globalIndexAndTransform;
101 class PackedBoolList;
102 
103 /*---------------------------------------------------------------------------*\
104  Class globalMeshData Declaration
105 \*---------------------------------------------------------------------------*/
106 
107 class globalMeshData
108 {
109 
110  // Private Data
111 
112  //- Reference to mesh
113  const polyMesh& mesh_;
114 
115 
116  // Data related to the complete mesh
117 
118  //- Total number of points in the complete mesh
119  label nTotalPoints_;
120 
121  //- Total number of faces in the complete mesh
122  label nTotalFaces_;
123 
124  //- Total number of cells in the complete mesh
125  label nTotalCells_;
126 
127 
128  // Processor patch addressing (be careful if not running in parallel!)
129 
130  //- Processor topology class
131  processorTopology processorTopology_;
132 
133  //- List of processor patch labels
134  // (size of list = number of processor patches)
135  labelList processorPatches_;
136 
137  //- List of indices into processorPatches_ for each patch.
138  // Index = -1 for non-processor patches.
139  // (size of list = number of patches)
140  labelList processorPatchIndices_;
141 
142  //- processorPatchIndices_ of the neighbours processor patches
143  labelList processorPatchNeighbours_;
144 
145 
146  // Coupled point addressing
147  // This is addressing from coupled point to coupled points/faces/cells.
148  // This is a full schedule so includes points used by only two
149  // coupled patches.
150 
151  //- Patch of coupled faces. Additional patch edge to mesh edges
152  // correspondence:
153  // points: meshPoints(), meshPointMap()
154  // edges : meshEdges(), meshEdgeMap()
155  mutable autoPtr<indirectPrimitivePatch> coupledPatchPtr_;
156  mutable autoPtr<labelList> coupledPatchMeshEdgesPtr_;
157  mutable autoPtr<Map<label>> coupledPatchMeshEdgeMapPtr_;
158 
159  //- Global numbering for coupledPatch points
160  mutable autoPtr<globalIndex> globalPointNumberingPtr_;
161 
162  //- Global numbering for transforms
163  mutable autoPtr<globalIndexAndTransform> globalTransformsPtr_;
164 
165  // Coupled point to coupled points
166 
167  mutable autoPtr<labelListList> globalPointSlavesPtr_;
168  mutable autoPtr<labelListList> globalPointTransformedSlavesPtr_;
169  mutable autoPtr<distributionMap> globalPointSlavesMapPtr_;
170 
171  // Coupled edge to coupled edges
172 
173  mutable autoPtr<globalIndex> globalEdgeNumberingPtr_;
174  mutable autoPtr<labelListList> globalEdgeSlavesPtr_;
175  mutable autoPtr<labelListList> globalEdgeTransformedSlavesPtr_;
176  mutable autoPtr<PackedBoolList> globalEdgeOrientationPtr_;
177  mutable autoPtr<distributionMap> globalEdgeSlavesMapPtr_;
178 
179 
180  // Coupled point to boundary faces
181 
182  mutable autoPtr<globalIndex> globalBoundaryFaceNumberingPtr_;
183  mutable autoPtr<labelListList> globalPointBoundaryFacesPtr_;
184  mutable autoPtr<labelListList>
185  globalPointTransformedBoundaryFacesPtr_;
186  mutable autoPtr<distributionMap> globalPointBoundaryFacesMapPtr_;
187 
188  // Coupled point to boundary cells
189 
190  mutable autoPtr<labelList> boundaryCellsPtr_;
191  mutable autoPtr<globalIndex> globalBoundaryCellNumberingPtr_;
192  mutable autoPtr<labelListList> globalPointBoundaryCellsPtr_;
193  mutable autoPtr<labelListList>
194  globalPointTransformedBoundaryCellsPtr_;
195  mutable autoPtr<distributionMap> globalPointBoundaryCellsMapPtr_;
196 
197 
198  // Other: coupled point to coupled COLLOCATED points
199  mutable autoPtr<labelListList> globalCoPointSlavesPtr_;
200  mutable autoPtr<distributionMap> globalCoPointSlavesMapPtr_;
201 
202 
203 
204  // Globally shared point addressing
205 
206  //- Total number of global points
207  mutable label nGlobalPoints_;
208 
209  //- Indices of local points that are globally shared
210  mutable autoPtr<labelList> sharedPointLabelsPtr_;
211 
212  //- Indices of globally shared points in the master list
213  // This list contains all the shared points in the mesh
214  mutable autoPtr<labelList> sharedPointAddrPtr_;
215 
216  //- Shared point global labels.
217  // Global point index for every local shared point.
218  // Only valid if constructed with this information or if
219  // pointProcAddressing read.
220  mutable autoPtr<labelList> sharedPointGlobalLabelsPtr_;
221 
222 
223  // Globally shared edge addressing. Derived from shared points.
224  // All demand driven since don't want to construct edges always.
225 
226  //- Total number of global edges
227  mutable label nGlobalEdges_;
228 
229  //- Indices of local edges that are globally shared
230  mutable autoPtr<labelList> sharedEdgeLabelsPtr_;
231 
232  //- Indices of globally shared edge in the master list
233  // This list contains all the shared edges in the mesh
234  mutable autoPtr<labelList> sharedEdgeAddrPtr_;
235 
236 
237  // Private Member Functions
238 
239  //- Set up processor patch addressing
240  void initProcAddr();
241 
242  //- Helper function for shared edge addressing
243  static void countSharedEdges
244  (
245  const EdgeMap<labelList>&,
247  label&
248  );
249 
250  //- Calculate shared point addressing
251  void calcSharedPoints() const;
252 
253  //- Calculate shared edge addressing
254  void calcSharedEdges() const;
255 
256  //- Calculate global point addressing.
257  void calcGlobalPointSlaves() const;
258 
259 
260  // Global edge addressing
261 
262  //- Calculate connected points
263  void calcPointConnectivity(List<labelPairList>&) const;
264 
265  //- Calculate pointEdges and pointPoints addressing
266  void calcGlobalPointEdges
267  (
268  labelListList& globalPointEdges,
269  List<labelPairList>& globalPointPoints
270  ) const;
271 
272  //- Look up remote and local point and find using info the
273  // transforms to go from remotePoint to localPoint
274  label findTransform
275  (
276  const labelPairList& info,
277  const labelPair& remotePoint,
278  const label localPoint
279  ) const;
280 
281  //- Calculate global edge addressing.
282  void calcGlobalEdgeSlaves() const;
283 
284  //- Calculate orientation w.r.t. edge master.
285  void calcGlobalEdgeOrientation() const;
286 
287 
288  // Global boundary face/cell addressing
289 
290  //- Calculate coupled point to uncoupled boundary faces. Local only.
291  void calcPointBoundaryFaces(labelListList&) const;
292 
293  //- Calculate global point to global boundary face addressing.
294  void calcGlobalPointBoundaryFaces() const;
295 
296  //- Calculate global point to global boundary cell addressing.
297  void calcGlobalPointBoundaryCells() const;
298 
299 
300  // Other
301 
302  // Point to collocated points. Note that not all points on
303  // coupled patches now have a master! (since points on either
304  // side of a cyclic are not connected). So check whether the map
305  // reaches all points and decide who is master, slave and who is
306  // its own master. Maybe store as well?
307 
308  void calcGlobalCoPointSlaves() const;
309 
310 
311 public:
312 
313  // Public class
314 
315  // To combineReduce a List. Just appends all lists.
316  template<class T>
317  class ListPlusEqOp
318  {
319 
320  public:
321 
322  void operator()(T& x, const T& y) const
323  {
324  label n = x.size();
325 
326  x.setSize(x.size() + y.size());
327 
328  forAll(y, i)
329  {
330  x[n++] = y[i];
331  }
332  }
333  };
334 
335 
336  //- Runtime type information
337  ClassName("globalMeshData");
338 
339 
340  // Static Data Members
341 
342  //- Geometric tolerance (fraction of bounding box)
343  static const Foam::scalar matchTol_;
344 
345 
346  // Constructors
347 
348  //- Construct from mesh, derive rest (does parallel communication!)
349  globalMeshData(const polyMesh& mesh);
350 
351  //- Disallow default bitwise copy construction
352  globalMeshData(const globalMeshData&) = delete;
353 
354 
355  //- Destructor
356  ~globalMeshData();
357 
358  //- Remove all demand driven data
359  void clearOut();
360 
361 
362  // Member Functions
363 
364  // Access
365 
366  //- Return the mesh reference
367  const polyMesh& mesh() const
368  {
369  return mesh_;
370  }
371 
372  //- Does the mesh contain processor patches? (also valid when
373  // not running parallel)
374  bool parallel() const
375  {
376  return processorPatches_.size() > 0;
377  }
378 
379  //- Return total number of points in decomposed mesh. Not
380  // compensated for duplicate points!
381  label nTotalPoints() const
382  {
383  return nTotalPoints_;
384  }
385 
386  //- Return total number of faces in decomposed mesh. Not
387  // compensated for duplicate faces!
388  label nTotalFaces() const
389  {
390  return nTotalFaces_;
391  }
392 
393  //- Return total number of cells in decomposed mesh.
394  label nTotalCells() const
395  {
396  return nTotalCells_;
397  }
398 
399 
400  // Processor patch addressing (be careful when not running in parallel)
401 
402  //- Return the processor-processor connection table
403  const labelListList& procNbrProcs() const
404  {
405  return processorTopology_.procNbrProcs();
406  }
407 
408  //- Order in which the patches should be initialised/evaluated
409  // corresponding to the schedule
410  const lduSchedule& patchSchedule() const
411  {
412  return processorTopology_.patchSchedule();
413  }
414 
415  //- Return list of processor patch labels
416  // (size of list = number of processor patches)
417  const labelList& processorPatches() const
418  {
419  return processorPatches_;
420  }
421 
422  //- Return list of indices into processorPatches_ for each patch.
423  // Index = -1 for non-processor parches.
424  // (size of list = number of patches)
425  const labelList& processorPatchIndices() const
426  {
427  return processorPatchIndices_;
428  }
429 
430  //- Return processorPatchIndices of the neighbours
431  // processor patches. -1 if not running parallel.
432  const labelList& processorPatchNeighbours() const
433  {
434  return processorPatchNeighbours_;
435  }
436 
437 
438  // Globally shared point addressing
439 
440  //- Return number of globally shared points
441  label nGlobalPoints() const;
442 
443  //- Return indices of local points that are globally shared
444  const labelList& sharedPointLabels() const;
445 
446  //- Return addressing into the complete globally shared points
447  // list
448  // Note: It is assumed that a (never constructed) complete
449  // list of globally shared points exists. The set of shared
450  // points on the current processor is a subset of all shared
451  // points. Shared point addressing gives the index in the
452  // list of all globally shared points for each of the locally
453  // shared points.
454  const labelList& sharedPointAddr() const;
455 
456  //- Return shared point global labels. Tries to read
457  // 'pointProcAddressing' and returns list or -1 if none
458  // available.
459  const labelList& sharedPointGlobalLabels() const;
460 
461  //- Collect coordinates of shared points on all processors.
462  // Does parallel communication. Not valid for points on
463  // cyclics since these combine into a single shared point but
464  // span multiple locations.
465  pointField sharedPoints() const;
466 
467 
468 
469  // Globally shared edge addressing
470 
471  //- Return number of globally shared edges. Demand-driven
472  // calculation so call needs to be synchronous among processors!
473  label nGlobalEdges() const;
474 
475  //- Return indices of local edges that are globally shared.
476  // Demand-driven
477  // calculation so call needs to be synchronous among processors!
478  const labelList& sharedEdgeLabels() const;
479 
480  //- Return addressing into the complete globally shared edge
481  // list. The set of shared
482  // edges on the current processor is a subset of all shared
483  // edges. Shared edge addressing gives the index in the
484  // list of all globally shared edges for each of the locally
485  // shared edges.
486  // Demand-driven
487  // calculation so call needs to be synchronous among processors!
488  const labelList& sharedEdgeAddr() const;
489 
490 
491 
492  // Global master - slave point communication
493 
494  //- Return patch of all coupled faces
495  const indirectPrimitivePatch& coupledPatch() const;
496 
497  //- Return map from coupledPatch edges to mesh edges
498  const labelList& coupledPatchMeshEdges() const;
499 
500  //- Return map from mesh edges to coupledPatch edges
501  const Map<label>& coupledPatchMeshEdgeMap() const;
502 
503  //- Global transforms numbering
505 
506  //- Helper: synchronise data with transforms
507  template<class Type, class CombineOp, class TransformOp>
508  static void syncData
509  (
511  const labelListList& slaves,
512  const labelListList& transformedSlaves,
513  const distributionMap& slavesMap,
515  const CombineOp& cop,
516  const TransformOp& top
517  );
518 
519  //- Helper: synchronise data without transforms
520  template<class Type, class CombineOp>
521  static void syncData
522  (
524  const labelListList& slaves,
525  const labelListList& transformedSlaves,
526  const distributionMap& slavesMap,
527  const CombineOp& cop
528  );
529 
530 
531  // Coupled point to coupled points. Coupled points are
532  // points on any coupled patch.
533 
534  //- Numbering of coupled points is according to coupledPatch.
535  const globalIndex& globalPointNumbering() const;
536  const labelListList& globalPointSlaves() const;
538  const distributionMap& globalPointSlavesMap() const;
539  //- Helper to synchronise coupled patch point data
540  template<class Type, class CombineOp, class TransformOp>
541  void syncPointData
542  (
544  const CombineOp& cop,
545  const TransformOp& top
546  ) const;
547 
548  // Coupled edge to coupled edges.
549 
550  const globalIndex& globalEdgeNumbering() const;
551  const labelListList& globalEdgeSlaves() const;
553  const distributionMap& globalEdgeSlavesMap() const;
554  //- Is my edge same orientation as master edge
555  const PackedBoolList& globalEdgeOrientation() const;
556 
557  // Collocated point to collocated point
558 
559  const labelListList& globalCoPointSlaves() const;
561 
562  // Coupled point to boundary faces. These are uncoupled boundary
563  // faces only but include empty patches.
564 
565  //- Numbering of boundary faces is face-mesh.nInternalFaces()
569  const;
571 
572  // Coupled point to boundary cell
573 
574  //- From boundary cell to mesh cell
575  const labelList& boundaryCells() const;
576 
577  //- Numbering of boundary cells is according to boundaryCells()
581  const;
583 
584 
585  // Other
586 
587  //- Helper for merging (collocated!) mesh point data.
588  // Determines:
589  // - my unique indices
590  // - global numbering over all unique indices
591  // - the global number for all local points (so this will
592  // be local for my unique points)
594  (
595  labelList& pointToGlobal,
596  labelList& uniquePoints
597  ) const;
598 
599  //- Helper for merging (collocated!) patch point data.
600  // Takes maps from:
601  // local points to/from mesh. Determines
602  // - my unique points. These are mesh point indices, not patch
603  // point indices.
604  // - global numbering over all unique indices.
605  // - the global number for all local points.
607  (
608  const labelList& meshPoints,
609  const Map<label>& meshPointMap,
610  labelList& pointToGlobal,
611  labelList& uniqueMeshPoints
612  ) const;
613 
614 
615  // Edit
616 
617  //- Update for moving points.
618  void movePoints(const pointField& newPoints);
619 
620  //- Change global mesh data given a topological change. Does a
621  // full parallel analysis to determine shared points and
622  // boundaries.
623  void topoChange();
624 
625 
626  // Member Operators
627 
628  //- Disallow default bitwise assignment
629  void operator=(const globalMeshData&) = delete;
630 };
631 
632 
633 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
634 
635 } // End namespace Foam
636 
637 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
638 
639 #ifdef NoRepository
640  #include "globalMeshDataTemplates.C"
641 #endif
642 
643 
644 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
645 
646 #endif
647 
648 // ************************************************************************* //
scalar y
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Map from edge (expressed as its endpoints) to value.
Definition: EdgeMap.H:50
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
A bit-packed bool list.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Class containing processor-to-processor mapping information.
Determination and storage of the possible independent transforms introduced by coupledPolyPatches,...
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
void operator()(T &x, const T &y) const
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const PackedBoolList & globalEdgeOrientation() const
Is my edge same orientation as master edge.
const lduSchedule & patchSchedule() const
Order in which the patches should be initialised/evaluated.
void movePoints(const pointField &newPoints)
Update for moving points.
static void syncData(List< Type > &pointData, const labelListList &slaves, const labelListList &transformedSlaves, const distributionMap &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
const labelList & sharedPointAddr() const
Return addressing into the complete globally shared points.
void topoChange()
Change global mesh data given a topological change. Does a.
const labelListList & globalPointTransformedBoundaryCells() const
globalMeshData(const polyMesh &mesh)
Construct from mesh, derive rest (does parallel communication!)
label nTotalFaces() const
Return total number of faces in decomposed mesh. Not.
const labelListList & globalEdgeTransformedSlaves() const
const labelList & processorPatches() const
Return list of processor patch labels.
const Map< label > & coupledPatchMeshEdgeMap() const
Return map from mesh edges to coupledPatch edges.
const labelList & sharedEdgeAddr() const
Return addressing into the complete globally shared edge.
bool parallel() const
Does the mesh contain processor patches? (also valid when.
static const Foam::scalar matchTol_
Geometric tolerance (fraction of bounding box)
label nGlobalPoints() const
Return number of globally shared points.
const distributionMap & globalPointBoundaryFacesMap() const
const labelList & processorPatchIndices() const
Return list of indices into processorPatches_ for each patch.
const labelList & sharedPointLabels() const
Return indices of local points that are globally shared.
const labelListList & globalPointTransformedBoundaryFaces() const
const labelList & boundaryCells() const
From boundary cell to mesh cell.
const labelListList & globalPointBoundaryFaces() const
const globalIndex & globalBoundaryFaceNumbering() const
Numbering of boundary faces is face-mesh.nInternalFaces()
const distributionMap & globalEdgeSlavesMap() const
const distributionMap & globalPointBoundaryCellsMap() const
const distributionMap & globalPointSlavesMap() const
void operator=(const globalMeshData &)=delete
Disallow default bitwise assignment.
ClassName("globalMeshData")
Runtime type information.
label nGlobalEdges() const
Return number of globally shared edges. Demand-driven.
const labelList & coupledPatchMeshEdges() const
Return map from coupledPatch edges to mesh edges.
~globalMeshData()
Destructor.
autoPtr< globalIndex > mergePoints(labelList &pointToGlobal, labelList &uniquePoints) const
Helper for merging (collocated!) mesh point data.
const labelList & sharedPointGlobalLabels() const
Return shared point global labels. Tries to read.
label nTotalPoints() const
Return total number of points in decomposed mesh. Not.
const labelListList & globalCoPointSlaves() const
const distributionMap & globalCoPointSlavesMap() const
void syncPointData(List< Type > &pointData, const CombineOp &cop, const TransformOp &top) const
Helper to synchronise coupled patch point data.
pointField sharedPoints() const
Collect coordinates of shared points on all processors.
const globalIndex & globalBoundaryCellNumbering() const
Numbering of boundary cells is according to boundaryCells()
const labelListList & globalPointSlaves() const
const globalIndex & globalEdgeNumbering() const
const globalIndexAndTransform & globalTransforms() const
Global transforms numbering.
const labelList & sharedEdgeLabels() const
Return indices of local edges that are globally shared.
const labelListList & globalPointTransformedSlaves() const
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
const labelList & processorPatchNeighbours() const
Return processorPatchIndices of the neighbours.
const polyMesh & mesh() const
Return the mesh reference.
const labelListList & globalPointBoundaryCells() const
const labelListList & procNbrProcs() const
Return the processor-processor connection table.
void clearOut()
Remove all demand driven data.
label nTotalCells() const
Return total number of cells in decomposed mesh.
const labelListList & globalEdgeSlaves() const
const globalIndex & globalPointNumbering() const
Numbering of coupled points is according to coupledPatch.
Variant of pointEdgePoint with some transported additional data. WIP - should be templated on data li...
Definition: pointData.H:63
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const lduSchedule & patchSchedule() const
Order in which the patches should be initialised/evaluated.
const labelListList & procNbrProcs() const
Return the processor-processor connection table.
Namespace for OpenFOAM.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)