Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /* 00002 * ===================================================================================== 00003 * 00004 * Filename: TempestOnlineMapIO.cpp 00005 * 00006 * Description: All I/O implementations related to TempestOnlineMap 00007 * 00008 * Version: 1.0 00009 * Created: 02/06/2021 02:35:41 00010 * 00011 * Author: Vijay S. Mahadevan (vijaysm), [email protected] 00012 * Company: Argonne National Lab 00013 * 00014 * ===================================================================================== 00015 */ 00016 00017 #include "FiniteElementTools.h" 00018 #include "moab/Remapping/TempestOnlineMap.hpp" 00019 #include "moab/TupleList.hpp" 00020 00021 #ifdef MOAB_HAVE_NETCDFPAR 00022 #include "netcdfcpp_par.hpp" 00023 #else 00024 #include "netcdfcpp.h" 00025 #endif 00026 00027 #ifdef MOAB_HAVE_PNETCDF 00028 #include <pnetcdf.h> 00029 00030 #define ERR_PARNC( err ) \ 00031 if( err != NC_NOERR ) \ 00032 { \ 00033 fprintf( stderr, "Error at line %d: %s\n", __LINE__, ncmpi_strerror( err ) ); \ 00034 MPI_Abort( MPI_COMM_WORLD, 1 ); \ 00035 } 00036 00037 #endif 00038 00039 #ifdef MOAB_HAVE_MPI 00040 00041 #define MPI_CHK_ERR( err ) \ 00042 if( err ) \ 00043 { \ 00044 std::cout << "MPI Failure. ErrorCode (" << ( err ) << ") "; \ 00045 std::cout << "\nMPI Aborting... \n"; \ 00046 return moab::MB_FAILURE; \ 00047 } 00048 00049 int moab::TempestOnlineMap::rearrange_arrays_by_dofs( const std::vector< unsigned int >& gdofmap, 00050 DataArray1D< double >& vecFaceArea, 00051 DataArray1D< double >& dCenterLon, 00052 DataArray1D< double >& dCenterLat, 00053 DataArray2D< double >& dVertexLon, 00054 DataArray2D< double >& dVertexLat, 00055 std::vector< int >& masks, 00056 unsigned& N, // will have the local, after 00057 int& nv, 00058 int& maxdof ) 00059 { 00060 // first decide maxdof, for partitioning 00061 00062 unsigned int localmax = 0; 00063 for( unsigned i = 0; i < N; i++ ) 00064 if( gdofmap[i] > localmax ) localmax = gdofmap[i]; 00065 00066 int localMax[2]; 00067 int globalMax[2]; 00068 localMax[0] = localmax; 00069 localMax[1] = nv; 00070 // we also need to find out maximum of nv; if nv is 0 (no cells on a task), it will lead to 00071 // problems in gs transfer, because the size of the tuple depends on nv 00072 00073 MPI_Allreduce( localMax, globalMax, 2, MPI_INT, MPI_MAX, m_pcomm->comm() ); 00074 maxdof = globalMax[0]; 00075 nv = globalMax[1]; 00076 // maxdof is 0 based, so actual number is +1 00077 // maxdof 00078 // decide partitioning based on maxdof/size 00079 00080 int size_per_task = ( maxdof + 1 ) / size; // based on this, processor to process dof x is x/size_per_task 00081 // so we decide to reorder by actual dof, such that task 0 has dofs from [0 to size_per_task), etc 00082 moab::TupleList tl; 00083 unsigned numr = 2 * nv + 3; // doubles: area, centerlon, center lat, nv (vertex lon, vertex lat) 00084 tl.initialize( 3, 0, 0, numr, N ); // to proc, dof, then 00085 tl.enableWriteAccess(); 00086 // populate 00087 for( unsigned i = 0; i < N; i++ ) 00088 { 00089 int gdof = gdofmap[i]; 00090 int to_proc = gdof / size_per_task; 00091 int mask = masks[i]; 00092 if( to_proc >= size ) to_proc = size - 1; // the last ones go to last proc 00093 int n = tl.get_n(); 00094 tl.vi_wr[3 * n] = to_proc; 00095 tl.vi_wr[3 * n + 1] = gdof; 00096 tl.vi_wr[3 * n + 2] = mask; 00097 tl.vr_wr[n * numr] = vecFaceArea[i]; 00098 tl.vr_wr[n * numr + 1] = dCenterLon[i]; 00099 tl.vr_wr[n * numr + 2] = dCenterLat[i]; 00100 for( int j = 0; j < nv; j++ ) 00101 { 00102 tl.vr_wr[n * numr + 3 + j] = dVertexLon[i][j]; 00103 tl.vr_wr[n * numr + 3 + nv + j] = dVertexLat[i][j]; 00104 } 00105 tl.inc_n(); 00106 } 00107 00108 // now do the heavy communication 00109 00110 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl, 0 ); 00111 00112 // after communication, on each processor we should have tuples coming in 00113 // still need to order by global dofs; then rearrange input vectors 00114 moab::TupleList::buffer sort_buffer; 00115 sort_buffer.buffer_init( tl.get_n() ); 00116 tl.sort( 1, &sort_buffer ); 00117 // count how many are unique, and collapse 00118 int nb_unique = 1; 00119 for( unsigned i = 0; i < tl.get_n() - 1; i++ ) 00120 { 00121 if( tl.vi_wr[3 * i + 1] != tl.vi_wr[3 * i + 4] ) nb_unique++; 00122 } 00123 vecFaceArea.Allocate( nb_unique ); 00124 dCenterLon.Allocate( nb_unique ); 00125 dCenterLat.Allocate( nb_unique ); 00126 dVertexLon.Allocate( nb_unique, nv ); 00127 dVertexLat.Allocate( nb_unique, nv ); 00128 masks.resize( nb_unique ); 00129 int current_size = 1; 00130 vecFaceArea[0] = tl.vr_wr[0]; 00131 dCenterLon[0] = tl.vr_wr[1]; 00132 dCenterLat[0] = tl.vr_wr[2]; 00133 masks[0] = tl.vi_wr[2]; 00134 for( int j = 0; j < nv; j++ ) 00135 { 00136 dVertexLon[0][j] = tl.vr_wr[3 + j]; 00137 dVertexLat[0][j] = tl.vr_wr[3 + nv + j]; 00138 } 00139 for( unsigned i = 0; i < tl.get_n() - 1; i++ ) 00140 { 00141 int i1 = i + 1; 00142 if( tl.vi_wr[3 * i + 1] != tl.vi_wr[3 * i + 4] ) 00143 { 00144 vecFaceArea[current_size] = tl.vr_wr[i1 * numr]; 00145 dCenterLon[current_size] = tl.vr_wr[i1 * numr + 1]; 00146 dCenterLat[current_size] = tl.vr_wr[i1 * numr + 2]; 00147 for( int j = 0; j < nv; j++ ) 00148 { 00149 dVertexLon[current_size][j] = tl.vr_wr[i1 * numr + 3 + j]; 00150 dVertexLat[current_size][j] = tl.vr_wr[i1 * numr + 3 + nv + j]; 00151 } 00152 masks[current_size] = tl.vi_wr[3 * i1 + 2]; 00153 current_size++; 00154 } 00155 else 00156 { 00157 vecFaceArea[current_size - 1] += tl.vr_wr[i1 * numr]; // accumulate areas; will come here only for cgll ? 00158 } 00159 } 00160 00161 N = current_size; // or nb_unique, should be the same 00162 return 0; 00163 } 00164 #endif 00165 00166 /////////////////////////////////////////////////////////////////////////////// 00167 00168 moab::ErrorCode moab::TempestOnlineMap::WriteParallelMap( const std::string& strFilename ) 00169 { 00170 moab::ErrorCode rval; 00171 00172 size_t lastindex = strFilename.find_last_of( "." ); 00173 std::string extension = strFilename.substr( lastindex + 1, strFilename.size() ); 00174 00175 // Write the map file to disk in parallel 00176 if( extension == "nc" ) 00177 { 00178 /* Invoke the actual call to write the parallel map to disk in SCRIP format */ 00179 rval = this->WriteSCRIPMapFile( strFilename.c_str() );MB_CHK_ERR( rval ); 00180 } 00181 else 00182 { 00183 /* Write to the parallel H5M format */ 00184 rval = this->WriteHDF5MapFile( strFilename.c_str() );MB_CHK_ERR( rval ); 00185 } 00186 00187 return rval; 00188 } 00189 00190 /////////////////////////////////////////////////////////////////////////////// 00191 00192 moab::ErrorCode moab::TempestOnlineMap::WriteSCRIPMapFile( const std::string& strFilename ) 00193 { 00194 NcError error( NcError::silent_nonfatal ); 00195 00196 #ifdef MOAB_HAVE_NETCDFPAR 00197 bool is_independent = true; 00198 ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcFile::Replace, NcFile::Netcdf4 ); 00199 // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 ); 00200 #else 00201 NcFile ncMap( strFilename.c_str(), NcFile::Replace ); 00202 #endif 00203 00204 if( !ncMap.is_valid() ) 00205 { 00206 _EXCEPTION1( "Unable to open output map file \"%s\"", strFilename.c_str() ); 00207 } 00208 00209 // Attributes 00210 ncMap.add_att( "Title", "MOAB-TempestRemap Online Regridding Weight Generator" ); 00211 00212 /** 00213 * Need to get the global maximum of number of vertices per element 00214 * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for 00215 *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However, 00216 *when writing this out, other processes may have a different size for the same array. This is 00217 *hence a mess to consolidate in h5mtoscrip eventually. 00218 **/ 00219 00220 /* Let us compute all relevant data for the current original source mesh on the process */ 00221 DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea; 00222 DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat; 00223 DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat; 00224 if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD ) 00225 { 00226 this->InitializeCoordinatesFromMeshFV( 00227 *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat, 00228 ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ), /* fLatLon = false */ 00229 m_remapper->max_source_edges ); 00230 00231 vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() ); 00232 for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i ) 00233 vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i]; 00234 } 00235 else 00236 { 00237 DataArray3D< double > dataGLLJacobianSrc; 00238 this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon, 00239 dSourceCenterLat, dSourceVertexLon, dSourceVertexLat ); 00240 00241 // Generate the continuous Jacobian for input mesh 00242 GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc ); 00243 00244 if( m_srcDiscType == DiscretizationType_CGLL ) 00245 { 00246 GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, vecSourceFaceArea ); 00247 } 00248 else 00249 { 00250 GenerateDiscontinuousJacobian( dataGLLJacobianSrc, vecSourceFaceArea ); 00251 } 00252 } 00253 00254 if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD ) 00255 { 00256 this->InitializeCoordinatesFromMeshFV( 00257 *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat, 00258 ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ), /* fLatLon = false */ 00259 m_remapper->max_target_edges ); 00260 00261 vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() ); 00262 for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i ) 00263 { 00264 vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i]; 00265 } 00266 } 00267 else 00268 { 00269 DataArray3D< double > dataGLLJacobianDest; 00270 this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon, 00271 dTargetCenterLat, dTargetVertexLon, dTargetVertexLat ); 00272 00273 // Generate the continuous Jacobian for input mesh 00274 GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest ); 00275 00276 if( m_destDiscType == DiscretizationType_CGLL ) 00277 { 00278 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, vecTargetFaceArea ); 00279 } 00280 else 00281 { 00282 GenerateDiscontinuousJacobian( dataGLLJacobianDest, vecTargetFaceArea ); 00283 } 00284 } 00285 00286 // Map dimensions 00287 unsigned nA = ( vecSourceFaceArea.GetRows() ); 00288 unsigned nB = ( vecTargetFaceArea.GetRows() ); 00289 00290 std::vector< int > masksA, masksB; 00291 ErrorCode rval = m_remapper->GetIMasks( moab::Remapper::SourceMesh, masksA );MB_CHK_SET_ERR( rval, "Trouble getting masks for source" ); 00292 rval = m_remapper->GetIMasks( moab::Remapper::TargetMesh, masksB );MB_CHK_SET_ERR( rval, "Trouble getting masks for target" ); 00293 00294 // Number of nodes per Face 00295 int nSourceNodesPerFace = dSourceVertexLon.GetColumns(); 00296 int nTargetNodesPerFace = dTargetVertexLon.GetColumns(); 00297 // if source or target cells have triangles at poles, center of those triangles need to come from 00298 // the original quad, not from center in 3d, converted to 2d again 00299 // start copy OnlineMap.cpp tempestremap 00300 // right now, do this only for source mesh; copy the logic for target mesh 00301 00302 for( unsigned i = 0; i < nA; i++ ) 00303 { 00304 const Face& face = m_meshInput->faces[i]; 00305 00306 int nNodes = face.edges.size(); 00307 int indexNodeAtPole = -1; 00308 if( 3 == nNodes ) // check if one node at the poles 00309 { 00310 for( int j = 0; j < nNodes; j++ ) 00311 if( fabs( fabs( dSourceVertexLat[i][j] ) - 90.0 ) < 1.0e-12 ) 00312 { 00313 indexNodeAtPole = j; 00314 break; 00315 } 00316 } 00317 if( indexNodeAtPole < 0 ) continue; // continue i loop, do nothing 00318 // recompute center of cell, from 3d data; add one 2 nodes at pole, and average 00319 int nodeAtPole = face[indexNodeAtPole]; // use the overloaded operator 00320 Node nodePole = m_meshInput->nodes[nodeAtPole]; 00321 Node newCenter = nodePole * 2; 00322 for( int j = 1; j < nNodes; j++ ) 00323 { 00324 int indexi = ( indexNodeAtPole + j ) % nNodes; // nNodes is 3 ! 00325 const Node& node = m_meshInput->nodes[face[indexi]]; 00326 newCenter = newCenter + node; 00327 } 00328 newCenter = newCenter * 0.25; 00329 newCenter = newCenter.Normalized(); 00330 00331 #ifdef VERBOSE 00332 double iniLon = dSourceCenterLon[i], iniLat = dSourceCenterLat[i]; 00333 #endif 00334 // dSourceCenterLon, dSourceCenterLat 00335 XYZtoRLL_Deg( newCenter.x, newCenter.y, newCenter.z, dSourceCenterLon[i], dSourceCenterLat[i] ); 00336 #ifdef VERBOSE 00337 std::cout << " modify center of triangle from " << iniLon << " " << iniLat << " to " << dSourceCenterLon[i] 00338 << " " << dSourceCenterLat[i] << "\n"; 00339 #endif 00340 } 00341 00342 // first move data if in parallel 00343 #if defined( MOAB_HAVE_MPI ) 00344 int max_row_dof, max_col_dof; // output; arrays will be re-distributed in chunks [maxdof/size] 00345 // if (size > 1) 00346 { 00347 00348 int ierr = rearrange_arrays_by_dofs( srccol_gdofmap, vecSourceFaceArea, dSourceCenterLon, dSourceCenterLat, 00349 dSourceVertexLon, dSourceVertexLat, masksA, nA, nSourceNodesPerFace, 00350 max_col_dof ); // now nA will be close to maxdof/size 00351 if( ierr != 0 ) 00352 { 00353 _EXCEPTION1( "Unable to arrange source data %d ", nA ); 00354 } 00355 // rearrange target data: (nB) 00356 // 00357 ierr = rearrange_arrays_by_dofs( row_gdofmap, vecTargetFaceArea, dTargetCenterLon, dTargetCenterLat, 00358 dTargetVertexLon, dTargetVertexLat, masksB, nB, nTargetNodesPerFace, 00359 max_row_dof ); // now nA will be close to maxdof/size 00360 if( ierr != 0 ) 00361 { 00362 _EXCEPTION1( "Unable to arrange target data %d ", nB ); 00363 } 00364 } 00365 #endif 00366 00367 // Number of non-zeros in the remap matrix operator 00368 int nS = m_weightMatrix.nonZeros(); 00369 00370 #if defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_NETCDFPAR ) 00371 int locbuf[5] = {(int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace}; 00372 int offbuf[3] = {0, 0, 0}; 00373 int globuf[5] = {0, 0, 0, 0, 0}; 00374 MPI_Scan( locbuf, offbuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() ); 00375 MPI_Allreduce( locbuf, globuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() ); 00376 MPI_Allreduce( &locbuf[3], &globuf[3], 2, MPI_INT, MPI_MAX, m_pcomm->comm() ); 00377 00378 // MPI_Scan is inclusive of data in current rank; modify accordingly. 00379 offbuf[0] -= nA; 00380 offbuf[1] -= nB; 00381 offbuf[2] -= nS; 00382 00383 #else 00384 int offbuf[3] = {0, 0, 0}; 00385 int globuf[5] = {(int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace}; 00386 #endif 00387 00388 // Write output dimensions entries 00389 unsigned nSrcGridDims = ( m_vecSourceDimSizes.size() ); 00390 unsigned nDstGridDims = ( m_vecTargetDimSizes.size() ); 00391 00392 NcDim* dimSrcGridRank = ncMap.add_dim( "src_grid_rank", nSrcGridDims ); 00393 NcDim* dimDstGridRank = ncMap.add_dim( "dst_grid_rank", nDstGridDims ); 00394 00395 NcVar* varSrcGridDims = ncMap.add_var( "src_grid_dims", ncInt, dimSrcGridRank ); 00396 NcVar* varDstGridDims = ncMap.add_var( "dst_grid_dims", ncInt, dimDstGridRank ); 00397 00398 #ifdef MOAB_HAVE_NETCDFPAR 00399 ncMap.enable_var_par_access( varSrcGridDims, is_independent ); 00400 ncMap.enable_var_par_access( varDstGridDims, is_independent ); 00401 #endif 00402 00403 char szDim[64]; 00404 if( ( nSrcGridDims == 1 ) && ( m_vecSourceDimSizes[0] != (int)nA ) ) 00405 { 00406 varSrcGridDims->put( &globuf[0], 1 ); 00407 varSrcGridDims->add_att( "name0", "num_dof" ); 00408 } 00409 else 00410 { 00411 for( unsigned i = 0; i < m_vecSourceDimSizes.size(); i++ ) 00412 { 00413 int tmp = ( i == 0 ? globuf[0] : m_vecSourceDimSizes[i] ); 00414 varSrcGridDims->set_cur( nSrcGridDims - i - 1 ); 00415 varSrcGridDims->put( &( tmp ), 1 ); 00416 } 00417 00418 for( unsigned i = 0; i < m_vecSourceDimSizes.size(); i++ ) 00419 { 00420 sprintf( szDim, "name%i", i ); 00421 varSrcGridDims->add_att( szDim, m_vecSourceDimNames[nSrcGridDims - i - 1].c_str() ); 00422 } 00423 } 00424 00425 if( ( nDstGridDims == 1 ) && ( m_vecTargetDimSizes[0] != (int)nB ) ) 00426 { 00427 varDstGridDims->put( &globuf[1], 1 ); 00428 varDstGridDims->add_att( "name0", "num_dof" ); 00429 } 00430 else 00431 { 00432 for( unsigned i = 0; i < m_vecTargetDimSizes.size(); i++ ) 00433 { 00434 int tmp = ( i == 0 ? globuf[1] : m_vecTargetDimSizes[i] ); 00435 varDstGridDims->set_cur( nDstGridDims - i - 1 ); 00436 varDstGridDims->put( &( tmp ), 1 ); 00437 } 00438 00439 for( unsigned i = 0; i < m_vecTargetDimSizes.size(); i++ ) 00440 { 00441 sprintf( szDim, "name%i", i ); 00442 varDstGridDims->add_att( szDim, m_vecTargetDimNames[nDstGridDims - i - 1].c_str() ); 00443 } 00444 } 00445 00446 // Source and Target mesh resolutions 00447 NcDim* dimNA = ncMap.add_dim( "n_a", globuf[0] ); 00448 NcDim* dimNB = ncMap.add_dim( "n_b", globuf[1] ); 00449 00450 // Number of nodes per Face 00451 NcDim* dimNVA = ncMap.add_dim( "nv_a", globuf[3] ); 00452 NcDim* dimNVB = ncMap.add_dim( "nv_b", globuf[4] ); 00453 00454 // Write coordinates 00455 NcVar* varYCA = ncMap.add_var( "yc_a", ncDouble, dimNA ); 00456 NcVar* varYCB = ncMap.add_var( "yc_b", ncDouble, dimNB ); 00457 00458 NcVar* varXCA = ncMap.add_var( "xc_a", ncDouble, dimNA ); 00459 NcVar* varXCB = ncMap.add_var( "xc_b", ncDouble, dimNB ); 00460 00461 NcVar* varYVA = ncMap.add_var( "yv_a", ncDouble, dimNA, dimNVA ); 00462 NcVar* varYVB = ncMap.add_var( "yv_b", ncDouble, dimNB, dimNVB ); 00463 00464 NcVar* varXVA = ncMap.add_var( "xv_a", ncDouble, dimNA, dimNVA ); 00465 NcVar* varXVB = ncMap.add_var( "xv_b", ncDouble, dimNB, dimNVB ); 00466 00467 // Write masks 00468 NcVar* varMaskA = ncMap.add_var( "mask_a", ncInt, dimNA ); 00469 NcVar* varMaskB = ncMap.add_var( "mask_b", ncInt, dimNB ); 00470 00471 #ifdef MOAB_HAVE_NETCDFPAR 00472 ncMap.enable_var_par_access( varYCA, is_independent ); 00473 ncMap.enable_var_par_access( varYCB, is_independent ); 00474 ncMap.enable_var_par_access( varXCA, is_independent ); 00475 ncMap.enable_var_par_access( varXCB, is_independent ); 00476 ncMap.enable_var_par_access( varYVA, is_independent ); 00477 ncMap.enable_var_par_access( varYVB, is_independent ); 00478 ncMap.enable_var_par_access( varXVA, is_independent ); 00479 ncMap.enable_var_par_access( varXVB, is_independent ); 00480 ncMap.enable_var_par_access( varMaskA, is_independent ); 00481 ncMap.enable_var_par_access( varMaskB, is_independent ); 00482 #endif 00483 00484 varYCA->add_att( "units", "degrees" ); 00485 varYCB->add_att( "units", "degrees" ); 00486 00487 varXCA->add_att( "units", "degrees" ); 00488 varXCB->add_att( "units", "degrees" ); 00489 00490 varYVA->add_att( "units", "degrees" ); 00491 varYVB->add_att( "units", "degrees" ); 00492 00493 varXVA->add_att( "units", "degrees" ); 00494 varXVB->add_att( "units", "degrees" ); 00495 00496 // Verify dimensionality 00497 if( dSourceCenterLon.GetRows() != nA ) 00498 { 00499 _EXCEPTIONT( "Mismatch between dSourceCenterLon and nA" ); 00500 } 00501 if( dSourceCenterLat.GetRows() != nA ) 00502 { 00503 _EXCEPTIONT( "Mismatch between dSourceCenterLat and nA" ); 00504 } 00505 if( dTargetCenterLon.GetRows() != nB ) 00506 { 00507 _EXCEPTIONT( "Mismatch between dTargetCenterLon and nB" ); 00508 } 00509 if( dTargetCenterLat.GetRows() != nB ) 00510 { 00511 _EXCEPTIONT( "Mismatch between dTargetCenterLat and nB" ); 00512 } 00513 if( dSourceVertexLon.GetRows() != nA ) 00514 { 00515 _EXCEPTIONT( "Mismatch between dSourceVertexLon and nA" ); 00516 } 00517 if( dSourceVertexLat.GetRows() != nA ) 00518 { 00519 _EXCEPTIONT( "Mismatch between dSourceVertexLat and nA" ); 00520 } 00521 if( dTargetVertexLon.GetRows() != nB ) 00522 { 00523 _EXCEPTIONT( "Mismatch between dTargetVertexLon and nB" ); 00524 } 00525 if( dTargetVertexLat.GetRows() != nB ) 00526 { 00527 _EXCEPTIONT( "Mismatch between dTargetVertexLat and nB" ); 00528 } 00529 00530 varYCA->set_cur( (long)offbuf[0] ); 00531 varYCA->put( &( dSourceCenterLat[0] ), nA ); 00532 varYCB->set_cur( (long)offbuf[1] ); 00533 varYCB->put( &( dTargetCenterLat[0] ), nB ); 00534 00535 varXCA->set_cur( (long)offbuf[0] ); 00536 varXCA->put( &( dSourceCenterLon[0] ), nA ); 00537 varXCB->set_cur( (long)offbuf[1] ); 00538 varXCB->put( &( dTargetCenterLon[0] ), nB ); 00539 00540 varYVA->set_cur( (long)offbuf[0] ); 00541 varYVA->put( &( dSourceVertexLat[0][0] ), nA, nSourceNodesPerFace ); 00542 varYVB->set_cur( (long)offbuf[1] ); 00543 varYVB->put( &( dTargetVertexLat[0][0] ), nB, nTargetNodesPerFace ); 00544 00545 varXVA->set_cur( (long)offbuf[0] ); 00546 varXVA->put( &( dSourceVertexLon[0][0] ), nA, nSourceNodesPerFace ); 00547 varXVB->set_cur( (long)offbuf[1] ); 00548 varXVB->put( &( dTargetVertexLon[0][0] ), nB, nTargetNodesPerFace ); 00549 00550 varMaskA->set_cur( (long)offbuf[0] ); 00551 varMaskA->put( &( masksA[0] ), nA ); 00552 varMaskB->set_cur( (long)offbuf[1] ); 00553 varMaskB->put( &( masksB[0] ), nB ); 00554 00555 // Write areas 00556 NcVar* varAreaA = ncMap.add_var( "area_a", ncDouble, dimNA ); 00557 #ifdef MOAB_HAVE_NETCDFPAR 00558 ncMap.enable_var_par_access( varAreaA, is_independent ); 00559 #endif 00560 varAreaA->set_cur( (long)offbuf[0] ); 00561 varAreaA->put( &( vecSourceFaceArea[0] ), nA ); 00562 00563 NcVar* varAreaB = ncMap.add_var( "area_b", ncDouble, dimNB ); 00564 #ifdef MOAB_HAVE_NETCDFPAR 00565 ncMap.enable_var_par_access( varAreaB, is_independent ); 00566 #endif 00567 varAreaB->set_cur( (long)offbuf[1] ); 00568 varAreaB->put( &( vecTargetFaceArea[0] ), nB ); 00569 00570 // Write SparseMatrix entries 00571 DataArray1D< int > vecRow( nS ); 00572 DataArray1D< int > vecCol( nS ); 00573 DataArray1D< double > vecS( nS ); 00574 DataArray1D< double > dFracA( nA ); 00575 DataArray1D< double > dFracB( nB ); 00576 00577 moab::TupleList tlValRow, tlValCol; 00578 unsigned numr = 1; // 00579 // value has to be sent to processor row/nB for for fracA and col/nA for fracB 00580 // vecTargetArea (indexRow ) has to be sent for fracA (index col?) 00581 // vecTargetFaceArea will have to be sent to col index, with its index ! 00582 tlValRow.initialize( 2, 0, 0, numr, nS ); // to proc(row), global row , value 00583 tlValCol.initialize( 3, 0, 0, numr, nS ); // to proc(col), global row / col, value 00584 tlValRow.enableWriteAccess(); 00585 tlValCol.enableWriteAccess(); 00586 /* 00587 * 00588 dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ]; 00589 dFracB[ row ] += val ; 00590 */ 00591 int offset = 0; 00592 #if defined( MOAB_HAVE_MPI ) 00593 int nAbase = ( max_col_dof + 1 ) / size; // it is nA, except last rank ( == size - 1 ) 00594 int nBbase = ( max_row_dof + 1 ) / size; // it is nB, except last rank ( == size - 1 ) 00595 #endif 00596 for( int i = 0; i < m_weightMatrix.outerSize(); ++i ) 00597 { 00598 for( WeightMatrix::InnerIterator it( m_weightMatrix, i ); it; ++it ) 00599 { 00600 vecRow[offset] = 1 + this->GetRowGlobalDoF( it.row() ); // row index 00601 vecCol[offset] = 1 + this->GetColGlobalDoF( it.col() ); // col index 00602 vecS[offset] = it.value(); // value 00603 00604 #if defined( MOAB_HAVE_MPI ) 00605 { 00606 // value M(row, col) will contribute to procRow and procCol values for fracA and fracB 00607 int procRow = ( vecRow[offset] - 1 ) / nBbase; 00608 if( procRow >= size ) procRow = size - 1; 00609 int procCol = ( vecCol[offset] - 1 ) / nAbase; 00610 if( procCol >= size ) procCol = size - 1; 00611 int nrInd = tlValRow.get_n(); 00612 tlValRow.vi_wr[2 * nrInd] = procRow; 00613 tlValRow.vi_wr[2 * nrInd + 1] = vecRow[offset] - 1; 00614 tlValRow.vr_wr[nrInd] = vecS[offset]; 00615 tlValRow.inc_n(); 00616 int ncInd = tlValCol.get_n(); 00617 tlValCol.vi_wr[3 * ncInd] = procCol; 00618 tlValCol.vi_wr[3 * ncInd + 1] = vecRow[offset] - 1; 00619 tlValCol.vi_wr[3 * ncInd + 2] = vecCol[offset] - 1; // this is column 00620 tlValCol.vr_wr[ncInd] = vecS[offset]; 00621 tlValCol.inc_n(); 00622 } 00623 #endif 00624 offset++; 00625 } 00626 } 00627 #if defined( MOAB_HAVE_MPI ) 00628 // need to send values for their row and col processors, to compute fractions there 00629 // now do the heavy communication 00630 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValCol, 0 ); 00631 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValRow, 0 ); 00632 00633 // we have now, for example, dFracB[ row ] += val ; 00634 // so we know that on current task, we received tlValRow 00635 // reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ]; 00636 // dFracB[ row ] += val ; 00637 for( unsigned i = 0; i < tlValRow.get_n(); i++ ) 00638 { 00639 // int fromProc = tlValRow.vi_wr[2 * i]; 00640 int gRowInd = tlValRow.vi_wr[2 * i + 1]; 00641 int localIndexRow = gRowInd - nBbase * rank; // modulo nBbase rank is from 0 to size - 1; 00642 double wgt = tlValRow.vr_wr[i]; 00643 assert( localIndexRow >= 0 ); 00644 assert( nB - localIndexRow > 0 ); 00645 dFracB[localIndexRow] += wgt; 00646 } 00647 // to compute dFracA we need vecTargetFaceArea[ row ]; we know the row, and we can get the proc we need it from 00648 00649 std::set< int > neededRows; 00650 for( unsigned i = 0; i < tlValCol.get_n(); i++ ) 00651 { 00652 int rRowInd = tlValCol.vi_wr[3 * i + 1]; 00653 neededRows.insert( rRowInd ); 00654 // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow 00655 } 00656 moab::TupleList tgtAreaReq; 00657 tgtAreaReq.initialize( 2, 0, 0, 0, neededRows.size() ); 00658 tgtAreaReq.enableWriteAccess(); 00659 for( std::set< int >::iterator sit = neededRows.begin(); sit != neededRows.end(); sit++ ) 00660 { 00661 int neededRow = *sit; 00662 int procRow = neededRow / nBbase; 00663 if( procRow >= size ) procRow = size - 1; 00664 int nr = tgtAreaReq.get_n(); 00665 tgtAreaReq.vi_wr[2 * nr] = procRow; 00666 tgtAreaReq.vi_wr[2 * nr + 1] = neededRow; 00667 tgtAreaReq.inc_n(); 00668 } 00669 00670 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaReq, 0 ); 00671 // we need to send back the tgtArea corresponding to row 00672 moab::TupleList tgtAreaInfo; // load it with tgtArea at row 00673 tgtAreaInfo.initialize( 2, 0, 0, 1, tgtAreaReq.get_n() ); 00674 tgtAreaInfo.enableWriteAccess(); 00675 for( unsigned i = 0; i < tgtAreaReq.get_n(); i++ ) 00676 { 00677 int from_proc = tgtAreaReq.vi_wr[2 * i]; 00678 int row = tgtAreaReq.vi_wr[2 * i + 1]; 00679 int locaIndexRow = row - rank * nBbase; 00680 double areaToSend = vecTargetFaceArea[locaIndexRow]; 00681 // int remoteIndex = tgtAreaReq.vi_wr[3*i + 2] ; 00682 00683 tgtAreaInfo.vi_wr[2 * i] = from_proc; // send back requested info 00684 tgtAreaInfo.vi_wr[2 * i + 1] = row; 00685 tgtAreaInfo.vr_wr[i] = areaToSend; // this will be tgt area at row 00686 tgtAreaInfo.inc_n(); 00687 } 00688 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaInfo, 0 ); 00689 00690 std::map< int, double > areaAtRow; 00691 for( unsigned i = 0; i < tgtAreaInfo.get_n(); i++ ) 00692 { 00693 // we have received from proc, value for row ! 00694 int row = tgtAreaInfo.vi_wr[2 * i + 1]; 00695 areaAtRow[row] = tgtAreaInfo.vr_wr[i]; 00696 } 00697 00698 // we have now for rows the 00699 // it is ordered by index, so: 00700 // now compute reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ]; 00701 // tgtAreaInfo will have at index i the area we need (from row) 00702 // there should be an easier way :( 00703 for( unsigned i = 0; i < tlValCol.get_n(); i++ ) 00704 { 00705 int rRowInd = tlValCol.vi_wr[3 * i + 1]; 00706 int colInd = tlValCol.vi_wr[3 * i + 2]; 00707 double val = tlValCol.vr_wr[i]; 00708 int localColInd = colInd - rank * nAbase; // < local nA 00709 // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow 00710 auto itMap = areaAtRow.find( rRowInd ); // it should be different from end 00711 if( itMap != areaAtRow.end() ) 00712 { 00713 double areaRow = itMap->second; // we fished a lot for this ! 00714 assert( localColInd < vecSourceFaceArea.GetRows() ); 00715 dFracA[localColInd] += val / vecSourceFaceArea[localColInd] * areaRow; 00716 } 00717 } 00718 00719 #endif 00720 // Load in data 00721 NcDim* dimNS = ncMap.add_dim( "n_s", globuf[2] ); 00722 00723 NcVar* varRow = ncMap.add_var( "row", ncInt, dimNS ); 00724 NcVar* varCol = ncMap.add_var( "col", ncInt, dimNS ); 00725 NcVar* varS = ncMap.add_var( "S", ncDouble, dimNS ); 00726 #ifdef MOAB_HAVE_NETCDFPAR 00727 ncMap.enable_var_par_access( varRow, is_independent ); 00728 ncMap.enable_var_par_access( varCol, is_independent ); 00729 ncMap.enable_var_par_access( varS, is_independent ); 00730 #endif 00731 00732 varRow->set_cur( (long)offbuf[2] ); 00733 varRow->put( &( vecRow[0] ), nS ); 00734 00735 varCol->set_cur( (long)offbuf[2] ); 00736 varCol->put( &( vecCol[0] ), nS ); 00737 00738 varS->set_cur( (long)offbuf[2] ); 00739 varS->put( &( vecS[0] ), nS ); 00740 00741 // Calculate and write fractional coverage arrays 00742 NcVar* varFracA = ncMap.add_var( "frac_a", ncDouble, dimNA ); 00743 #ifdef MOAB_HAVE_NETCDFPAR 00744 ncMap.enable_var_par_access( varFracA, is_independent ); 00745 #endif 00746 varFracA->add_att( "name", "fraction of target coverage of source dof" ); 00747 varFracA->add_att( "units", "unitless" ); 00748 varFracA->set_cur( (long)offbuf[0] ); 00749 varFracA->put( &( dFracA[0] ), nA ); 00750 00751 NcVar* varFracB = ncMap.add_var( "frac_b", ncDouble, dimNB ); 00752 #ifdef MOAB_HAVE_NETCDFPAR 00753 ncMap.enable_var_par_access( varFracB, is_independent ); 00754 #endif 00755 varFracB->add_att( "name", "fraction of source coverage of target dof" ); 00756 varFracB->add_att( "units", "unitless" ); 00757 varFracB->set_cur( (long)offbuf[1] ); 00758 varFracB->put( &( dFracB[0] ), nB ); 00759 00760 // Add global attributes 00761 // std::map<std::string, std::string>::const_iterator iterAttributes = 00762 // mapAttributes.begin(); 00763 // for (; iterAttributes != mapAttributes.end(); iterAttributes++) { 00764 // ncMap.add_att( 00765 // iterAttributes->first.c_str(), 00766 // iterAttributes->second.c_str()); 00767 // } 00768 00769 ncMap.close(); 00770 00771 return moab::MB_SUCCESS; 00772 } 00773 00774 /////////////////////////////////////////////////////////////////////////////// 00775 00776 moab::ErrorCode moab::TempestOnlineMap::WriteHDF5MapFile( const std::string& strOutputFile ) 00777 { 00778 moab::ErrorCode rval; 00779 00780 /** 00781 * Need to get the global maximum of number of vertices per element 00782 * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for 00783 *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However, 00784 *when writing this out, other processes may have a different size for the same array. This is 00785 *hence a mess to consolidate in h5mtoscrip eventually. 00786 **/ 00787 00788 /* Let us compute all relevant data for the current original source mesh on the process */ 00789 DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea; 00790 DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat; 00791 DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat; 00792 if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD ) 00793 { 00794 this->InitializeCoordinatesFromMeshFV( 00795 *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat, 00796 ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ) /* fLatLon = false */, 00797 m_remapper->max_source_edges ); 00798 00799 vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() ); 00800 for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i ) 00801 vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i]; 00802 } 00803 else 00804 { 00805 DataArray3D< double > dataGLLJacobianSrc; 00806 this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon, 00807 dSourceCenterLat, dSourceVertexLon, dSourceVertexLat ); 00808 00809 // Generate the continuous Jacobian for input mesh 00810 GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc ); 00811 00812 if( m_srcDiscType == DiscretizationType_CGLL ) 00813 { 00814 GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, m_meshInput->vecFaceArea ); 00815 } 00816 else 00817 { 00818 GenerateDiscontinuousJacobian( dataGLLJacobianSrc, m_meshInput->vecFaceArea ); 00819 } 00820 00821 vecSourceFaceArea.Allocate( m_meshInput->faces.size() * m_nDofsPEl_Src * m_nDofsPEl_Src ); 00822 int offset = 0; 00823 for( size_t e = 0; e < m_meshInput->faces.size(); e++ ) 00824 { 00825 for( int s = 0; s < m_nDofsPEl_Src; s++ ) 00826 { 00827 for( int t = 0; t < m_nDofsPEl_Src; t++ ) 00828 { 00829 vecSourceFaceArea[srccol_dtoc_dofmap[offset + s * m_nDofsPEl_Src + t]] = 00830 dataGLLJacobianSrc[s][t][e]; 00831 } 00832 } 00833 offset += m_nDofsPEl_Src * m_nDofsPEl_Src; 00834 } 00835 } 00836 00837 if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD ) 00838 { 00839 this->InitializeCoordinatesFromMeshFV( 00840 *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat, 00841 ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ) /* fLatLon = false */, 00842 m_remapper->max_target_edges ); 00843 00844 vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() ); 00845 for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i ) 00846 vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i]; 00847 } 00848 else 00849 { 00850 DataArray3D< double > dataGLLJacobianDest; 00851 this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon, 00852 dTargetCenterLat, dTargetVertexLon, dTargetVertexLat ); 00853 00854 // Generate the continuous Jacobian for input mesh 00855 GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest ); 00856 00857 if( m_destDiscType == DiscretizationType_CGLL ) 00858 { 00859 GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, m_meshOutput->vecFaceArea ); 00860 } 00861 else 00862 { 00863 GenerateDiscontinuousJacobian( dataGLLJacobianDest, m_meshOutput->vecFaceArea ); 00864 } 00865 00866 vecTargetFaceArea.Allocate( m_meshOutput->faces.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest ); 00867 int offset = 0; 00868 for( size_t e = 0; e < m_meshOutput->faces.size(); e++ ) 00869 { 00870 for( int s = 0; s < m_nDofsPEl_Dest; s++ ) 00871 { 00872 for( int t = 0; t < m_nDofsPEl_Dest; t++ ) 00873 { 00874 vecTargetFaceArea[row_dtoc_dofmap[offset + s * m_nDofsPEl_Dest + t]] = dataGLLJacobianDest[s][t][e]; 00875 } 00876 } 00877 offset += m_nDofsPEl_Dest * m_nDofsPEl_Dest; 00878 } 00879 } 00880 00881 moab::EntityHandle& m_meshOverlapSet = m_remapper->m_overlap_set; 00882 int tot_src_ents = m_remapper->m_source_entities.size(); 00883 int tot_tgt_ents = m_remapper->m_target_entities.size(); 00884 int tot_src_size = dSourceCenterLon.GetRows(); 00885 int tot_tgt_size = m_dTargetCenterLon.GetRows(); 00886 int tot_vsrc_size = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns(); 00887 int tot_vtgt_size = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns(); 00888 00889 const int weightMatNNZ = m_weightMatrix.nonZeros(); 00890 moab::Tag tagMapMetaData, tagMapIndexRow, tagMapIndexCol, tagMapValues, srcEleIDs, tgtEleIDs; 00891 rval = m_interface->tag_get_handle( "SMAT_DATA", 13, moab::MB_TYPE_INTEGER, tagMapMetaData, 00892 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00893 rval = m_interface->tag_get_handle( "SMAT_ROWS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexRow, 00894 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00895 rval = m_interface->tag_get_handle( "SMAT_COLS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexCol, 00896 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00897 rval = m_interface->tag_get_handle( "SMAT_VALS", weightMatNNZ, moab::MB_TYPE_DOUBLE, tagMapValues, 00898 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00899 rval = m_interface->tag_get_handle( "SourceGIDS", tot_src_size, moab::MB_TYPE_INTEGER, srcEleIDs, 00900 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00901 rval = m_interface->tag_get_handle( "TargetGIDS", tot_tgt_size, moab::MB_TYPE_INTEGER, tgtEleIDs, 00902 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00903 moab::Tag srcAreaValues, tgtAreaValues; 00904 rval = m_interface->tag_get_handle( "SourceAreas", tot_src_size, moab::MB_TYPE_DOUBLE, srcAreaValues, 00905 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00906 rval = m_interface->tag_get_handle( "TargetAreas", tot_tgt_size, moab::MB_TYPE_DOUBLE, tgtAreaValues, 00907 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00908 moab::Tag tagSrcCoordsCLon, tagSrcCoordsCLat, tagTgtCoordsCLon, tagTgtCoordsCLat; 00909 rval = m_interface->tag_get_handle( "SourceCoordCenterLon", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLon, 00910 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00911 rval = m_interface->tag_get_handle( "SourceCoordCenterLat", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLat, 00912 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00913 rval = m_interface->tag_get_handle( "TargetCoordCenterLon", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLon, 00914 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00915 rval = m_interface->tag_get_handle( "TargetCoordCenterLat", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLat, 00916 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00917 moab::Tag tagSrcCoordsVLon, tagSrcCoordsVLat, tagTgtCoordsVLon, tagTgtCoordsVLat; 00918 rval = m_interface->tag_get_handle( "SourceCoordVertexLon", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLon, 00919 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00920 rval = m_interface->tag_get_handle( "SourceCoordVertexLat", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLat, 00921 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00922 rval = m_interface->tag_get_handle( "TargetCoordVertexLon", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLon, 00923 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00924 rval = m_interface->tag_get_handle( "TargetCoordVertexLat", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLat, 00925 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00926 moab::Tag srcMaskValues, tgtMaskValues; 00927 if( m_iSourceMask.IsAttached() ) 00928 { 00929 rval = m_interface->tag_get_handle( "SourceMask", m_iSourceMask.GetRows(), moab::MB_TYPE_INTEGER, srcMaskValues, 00930 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00931 } 00932 if( m_iTargetMask.IsAttached() ) 00933 { 00934 rval = m_interface->tag_get_handle( "TargetMask", m_iTargetMask.GetRows(), moab::MB_TYPE_INTEGER, tgtMaskValues, 00935 moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" ); 00936 } 00937 00938 std::vector< int > smatrowvals( weightMatNNZ ), smatcolvals( weightMatNNZ ); 00939 std::vector< double > smatvals( weightMatNNZ ); 00940 // const double* smatvals = m_weightMatrix.valuePtr(); 00941 // Loop over the matrix entries and find the max global ID for rows and columns 00942 for( int k = 0, offset = 0; k < m_weightMatrix.outerSize(); ++k ) 00943 { 00944 for( moab::TempestOnlineMap::WeightMatrix::InnerIterator it( m_weightMatrix, k ); it; ++it, ++offset ) 00945 { 00946 smatrowvals[offset] = this->GetRowGlobalDoF( it.row() ); 00947 smatcolvals[offset] = this->GetColGlobalDoF( it.col() ); 00948 smatvals[offset] = it.value(); 00949 } 00950 } 00951 00952 /* Set the global IDs for the DoFs */ 00953 //// 00954 // col_gdofmap [ col_ldofmap [ 0 : local_ndofs ] ] = GDOF 00955 // row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF 00956 //// 00957 int maxrow = 0, maxcol = 0; 00958 std::vector< int > src_global_dofs( tot_src_size ), tgt_global_dofs( tot_tgt_size ); 00959 for( int i = 0; i < tot_src_size; ++i ) 00960 { 00961 src_global_dofs[i] = srccol_gdofmap[i]; 00962 maxcol = ( src_global_dofs[i] > maxcol ) ? src_global_dofs[i] : maxcol; 00963 } 00964 00965 for( int i = 0; i < tot_tgt_size; ++i ) 00966 { 00967 tgt_global_dofs[i] = row_gdofmap[i]; 00968 maxrow = ( tgt_global_dofs[i] > maxrow ) ? tgt_global_dofs[i] : maxrow; 00969 } 00970 00971 /////////////////////////////////////////////////////////////////////////// 00972 // The metadata in H5M file contains the following data: 00973 // 00974 // 1. n_a: Total source entities: (number of elements in source mesh) 00975 // 2. n_b: Total target entities: (number of elements in target mesh) 00976 // 3. nv_a: Max edge size of elements in source mesh 00977 // 4. nv_b: Max edge size of elements in target mesh 00978 // 5. maxrows: Number of rows in remap weight matrix 00979 // 6. maxcols: Number of cols in remap weight matrix 00980 // 7. nnz: Number of total nnz in sparse remap weight matrix 00981 // 8. np_a: The order of the field description on the source mesh: >= 1 00982 // 9. np_b: The order of the field description on the target mesh: >= 1 00983 // 10. method_a: The type of discretization for field on source mesh: [0 = FV, 1 = cGLL, 2 = 00984 // dGLL] 00985 // 11. method_b: The type of discretization for field on target mesh: [0 = FV, 1 = cGLL, 2 = 00986 // dGLL] 00987 // 12. conserved: Flag to specify whether the remap operator has conservation constraints: [0, 00988 // 1] 00989 // 13. monotonicity: Flags to specify whether the remap operator has monotonicity constraints: 00990 // [0, 1, 2] 00991 // 00992 /////////////////////////////////////////////////////////////////////////// 00993 int map_disc_details[6]; 00994 map_disc_details[0] = m_nDofsPEl_Src; 00995 map_disc_details[1] = m_nDofsPEl_Dest; 00996 map_disc_details[2] = ( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD 00997 ? 0 00998 : ( m_srcDiscType == DiscretizationType_CGLL ? 1 : 2 ) ); 00999 map_disc_details[3] = ( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD 01000 ? 0 01001 : ( m_destDiscType == DiscretizationType_CGLL ? 1 : 2 ) ); 01002 map_disc_details[4] = ( m_bConserved ? 1 : 0 ); 01003 map_disc_details[5] = m_iMonotonicity; 01004 01005 #ifdef MOAB_HAVE_MPI 01006 int loc_smatmetadata[13] = {tot_src_ents, 01007 tot_tgt_ents, 01008 m_remapper->max_source_edges, 01009 m_remapper->max_target_edges, 01010 maxrow + 1, 01011 maxcol + 1, 01012 weightMatNNZ, 01013 map_disc_details[0], 01014 map_disc_details[1], 01015 map_disc_details[2], 01016 map_disc_details[3], 01017 map_disc_details[4], 01018 map_disc_details[5]}; 01019 rval = m_interface->tag_set_data( tagMapMetaData, &m_meshOverlapSet, 1, &loc_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01020 int glb_smatmetadata[13] = {0, 01021 0, 01022 0, 01023 0, 01024 0, 01025 0, 01026 0, 01027 map_disc_details[0], 01028 map_disc_details[1], 01029 map_disc_details[2], 01030 map_disc_details[3], 01031 map_disc_details[4], 01032 map_disc_details[5]}; 01033 int loc_buf[7] = { 01034 tot_src_ents, tot_tgt_ents, weightMatNNZ, m_remapper->max_source_edges, m_remapper->max_target_edges, 01035 maxrow, maxcol}; 01036 int glb_buf[4] = {0, 0, 0, 0}; 01037 MPI_Reduce( &loc_buf[0], &glb_buf[0], 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() ); 01038 glb_smatmetadata[0] = glb_buf[0]; 01039 glb_smatmetadata[1] = glb_buf[1]; 01040 glb_smatmetadata[6] = glb_buf[2]; 01041 MPI_Reduce( &loc_buf[3], &glb_buf[0], 4, MPI_INT, MPI_MAX, 0, m_pcomm->comm() ); 01042 glb_smatmetadata[2] = glb_buf[0]; 01043 glb_smatmetadata[3] = glb_buf[1]; 01044 glb_smatmetadata[4] = glb_buf[2]; 01045 glb_smatmetadata[5] = glb_buf[3]; 01046 #else 01047 int glb_smatmetadata[13] = {tot_src_ents, 01048 tot_tgt_ents, 01049 m_remapper->max_source_edges, 01050 m_remapper->max_target_edges, 01051 maxrow, 01052 maxcol, 01053 weightMatNNZ, 01054 map_disc_details[0], 01055 map_disc_details[1], 01056 map_disc_details[2], 01057 map_disc_details[3], 01058 map_disc_details[4], 01059 map_disc_details[5]}; 01060 #endif 01061 // These values represent number of rows and columns. So should be 1-based. 01062 glb_smatmetadata[4]++; 01063 glb_smatmetadata[5]++; 01064 01065 if( this->is_root ) 01066 { 01067 std::cout << " " << this->rank << " Writing remap weights with size [" << glb_smatmetadata[4] << " X " 01068 << glb_smatmetadata[5] << "] and NNZ = " << glb_smatmetadata[6] << std::endl; 01069 EntityHandle root_set = 0; 01070 rval = m_interface->tag_set_data( tagMapMetaData, &root_set, 1, &glb_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01071 } 01072 01073 int dsize; 01074 const int numval = weightMatNNZ; 01075 const void* smatrowvals_d = smatrowvals.data(); 01076 const void* smatcolvals_d = smatcolvals.data(); 01077 const void* smatvals_d = smatvals.data(); 01078 rval = m_interface->tag_set_by_ptr( tagMapIndexRow, &m_meshOverlapSet, 1, &smatrowvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01079 rval = m_interface->tag_set_by_ptr( tagMapIndexCol, &m_meshOverlapSet, 1, &smatcolvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01080 rval = m_interface->tag_set_by_ptr( tagMapValues, &m_meshOverlapSet, 1, &smatvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01081 01082 /* Set the global IDs for the DoFs */ 01083 const void* srceleidvals_d = src_global_dofs.data(); 01084 const void* tgteleidvals_d = tgt_global_dofs.data(); 01085 dsize = src_global_dofs.size(); 01086 rval = m_interface->tag_set_by_ptr( srcEleIDs, &m_meshOverlapSet, 1, &srceleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01087 dsize = tgt_global_dofs.size(); 01088 rval = m_interface->tag_set_by_ptr( tgtEleIDs, &m_meshOverlapSet, 1, &tgteleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01089 01090 /* Set the source and target areas */ 01091 const void* srcareavals_d = vecSourceFaceArea; 01092 const void* tgtareavals_d = vecTargetFaceArea; 01093 dsize = tot_src_size; 01094 rval = m_interface->tag_set_by_ptr( srcAreaValues, &m_meshOverlapSet, 1, &srcareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01095 dsize = tot_tgt_size; 01096 rval = m_interface->tag_set_by_ptr( tgtAreaValues, &m_meshOverlapSet, 1, &tgtareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01097 01098 /* Set the coordinates for source and target center vertices */ 01099 const void* srccoordsclonvals_d = &dSourceCenterLon[0]; 01100 const void* srccoordsclatvals_d = &dSourceCenterLat[0]; 01101 dsize = dSourceCenterLon.GetRows(); 01102 rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLon, &m_meshOverlapSet, 1, &srccoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01103 rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLat, &m_meshOverlapSet, 1, &srccoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01104 const void* tgtcoordsclonvals_d = &m_dTargetCenterLon[0]; 01105 const void* tgtcoordsclatvals_d = &m_dTargetCenterLat[0]; 01106 dsize = vecTargetFaceArea.GetRows(); 01107 rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLon, &m_meshOverlapSet, 1, &tgtcoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01108 rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLat, &m_meshOverlapSet, 1, &tgtcoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01109 01110 /* Set the coordinates for source and target element vertices */ 01111 const void* srccoordsvlonvals_d = &( dSourceVertexLon[0][0] ); 01112 const void* srccoordsvlatvals_d = &( dSourceVertexLat[0][0] ); 01113 dsize = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns(); 01114 rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLon, &m_meshOverlapSet, 1, &srccoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01115 rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLat, &m_meshOverlapSet, 1, &srccoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01116 const void* tgtcoordsvlonvals_d = &( m_dTargetVertexLon[0][0] ); 01117 const void* tgtcoordsvlatvals_d = &( m_dTargetVertexLat[0][0] ); 01118 dsize = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns(); 01119 rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLon, &m_meshOverlapSet, 1, &tgtcoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01120 rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLat, &m_meshOverlapSet, 1, &tgtcoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01121 01122 /* Set the masks for source and target meshes if available */ 01123 if( m_iSourceMask.IsAttached() ) 01124 { 01125 const void* srcmaskvals_d = m_iSourceMask; 01126 dsize = m_iSourceMask.GetRows(); 01127 rval = m_interface->tag_set_by_ptr( srcMaskValues, &m_meshOverlapSet, 1, &srcmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01128 } 01129 01130 if( m_iTargetMask.IsAttached() ) 01131 { 01132 const void* tgtmaskvals_d = m_iTargetMask; 01133 dsize = m_iTargetMask.GetRows(); 01134 rval = m_interface->tag_set_by_ptr( tgtMaskValues, &m_meshOverlapSet, 1, &tgtmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" ); 01135 } 01136 01137 #ifdef MOAB_HAVE_MPI 01138 const char* writeOptions = ( this->size > 1 ? "PARALLEL=WRITE_PART" : "" ); 01139 #else 01140 const char* writeOptions = ""; 01141 #endif 01142 01143 // EntityHandle sets[3] = {m_remapper->m_source_set, m_remapper->m_target_set, m_remapper->m_overlap_set}; 01144 EntityHandle sets[1] = {m_remapper->m_overlap_set}; 01145 rval = m_interface->write_file( strOutputFile.c_str(), NULL, writeOptions, sets, 1 );MB_CHK_ERR( rval ); 01146 01147 #ifdef WRITE_SCRIP_FILE 01148 sstr.str( "" ); 01149 sstr << ctx.outFilename.substr( 0, lastindex ) << "_" << proc_id << ".nc"; 01150 std::map< std::string, std::string > mapAttributes; 01151 mapAttributes["Creator"] = "MOAB mbtempest workflow"; 01152 if( !ctx.proc_id ) std::cout << "Writing offline map to file: " << sstr.str() << std::endl; 01153 this->Write( strOutputFile.c_str(), mapAttributes, NcFile::Netcdf4 ); 01154 sstr.str( "" ); 01155 #endif 01156 01157 return moab::MB_SUCCESS; 01158 } 01159 01160 /////////////////////////////////////////////////////////////////////////////// 01161 01162 void print_progress( const int barWidth, const float progress, const char* message ) 01163 { 01164 std::cout << message << " ["; 01165 int pos = barWidth * progress; 01166 for( int i = 0; i < barWidth; ++i ) 01167 { 01168 if( i < pos ) 01169 std::cout << "="; 01170 else if( i == pos ) 01171 std::cout << ">"; 01172 else 01173 std::cout << " "; 01174 } 01175 std::cout << "] " << int( progress * 100.0 ) << " %\r"; 01176 std::cout.flush(); 01177 } 01178 01179 /////////////////////////////////////////////////////////////////////////////// 01180 01181 moab::ErrorCode moab::TempestOnlineMap::ReadParallelMap( const char* strSource, 01182 const std::vector< int >& owned_dof_ids, 01183 bool row_partition ) 01184 { 01185 NcError error( NcError::silent_nonfatal ); 01186 01187 NcVar *varRow = NULL, *varCol = NULL, *varS = NULL; 01188 int nS = 0, nA = 0, nB = 0; 01189 #ifdef MOAB_HAVE_PNETCDF 01190 // some variables will be used just in the case netcdfpar reader fails 01191 int ncfile = -1, ret = 0; 01192 int ndims, nvars, ngatts, unlimited; 01193 #endif 01194 #ifdef MOAB_HAVE_NETCDFPAR 01195 bool is_independent = true; 01196 ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 ); 01197 // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 ); 01198 #else 01199 NcFile ncMap( strSource, NcFile::ReadOnly ); 01200 #endif 01201 01202 #define CHECK_EXCEPTION( obj, type, varstr ) \ 01203 { \ 01204 if( obj == NULL ) \ 01205 { \ 01206 _EXCEPTION3( "Map file \"%s\" does not contain %s \"%s\"", strSource, type, varstr ); \ 01207 } \ 01208 } 01209 01210 // Read SparseMatrix entries 01211 01212 if( ncMap.is_valid() ) 01213 { 01214 NcDim* dimNS = ncMap.get_dim( "n_s" ); 01215 CHECK_EXCEPTION( dimNS, "dimension", "n_s" ); 01216 01217 NcDim* dimNA = ncMap.get_dim( "n_a" ); 01218 CHECK_EXCEPTION( dimNA, "dimension", "n_a" ); 01219 01220 NcDim* dimNB = ncMap.get_dim( "n_b" ); 01221 CHECK_EXCEPTION( dimNB, "dimension", "n_b" ); 01222 01223 // store total number of nonzeros 01224 nS = dimNS->size(); 01225 nA = dimNA->size(); 01226 nB = dimNB->size(); 01227 01228 varRow = ncMap.get_var( "row" ); 01229 CHECK_EXCEPTION( varRow, "variable", "row" ); 01230 01231 varCol = ncMap.get_var( "col" ); 01232 CHECK_EXCEPTION( varCol, "variable", "col" ); 01233 01234 varS = ncMap.get_var( "S" ); 01235 CHECK_EXCEPTION( varS, "variable", "S" ); 01236 01237 #ifdef MOAB_HAVE_NETCDFPAR 01238 ncMap.enable_var_par_access( varRow, is_independent ); 01239 ncMap.enable_var_par_access( varCol, is_independent ); 01240 ncMap.enable_var_par_access( varS, is_independent ); 01241 #endif 01242 } 01243 else 01244 { 01245 #ifdef MOAB_HAVE_PNETCDF 01246 // read the file using pnetcdf directly, in parallel; need to have MPI, we do not check that anymore 01247 // why build wth pnetcdf without MPI ? 01248 // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 ); 01249 ret = ncmpi_open( m_pcomm->comm(), strSource, NC_NOWRITE, MPI_INFO_NULL, &ncfile ); 01250 ERR_PARNC( ret ); // bail out completely 01251 ret = ncmpi_inq( ncfile, &ndims, &nvars, &ngatts, &unlimited ); 01252 ERR_PARNC( ret ); 01253 // find dimension ids for n_S 01254 int ins; 01255 ret = ncmpi_inq_dimid( ncfile, "n_s", &ins ); 01256 ERR_PARNC( ret ); 01257 MPI_Offset leng; 01258 ret = ncmpi_inq_dimlen( ncfile, ins, &leng ); 01259 ERR_PARNC( ret ); 01260 nS = (int)leng; 01261 ret = ncmpi_inq_dimid( ncfile, "n_b", &ins ); 01262 ERR_PARNC( ret ); 01263 ret = ncmpi_inq_dimlen( ncfile, ins, &leng ); 01264 ERR_PARNC( ret ); 01265 nB = (int)leng; 01266 #else 01267 _EXCEPTION1( "cannot read the file %s", strSource ); 01268 #endif 01269 } 01270 01271 // Let us declare the map object for every process 01272 SparseMatrix< double >& sparseMatrix = this->GetSparseMatrix(); 01273 01274 int localSize = nS / size; 01275 long offsetRead = rank * localSize; 01276 // leftovers on last rank 01277 if( rank == size - 1 ) 01278 { 01279 localSize += nS % size; 01280 } 01281 01282 std::vector< int > vecRow, vecCol; 01283 std::vector< double > vecS; 01284 vecRow.resize( localSize ); 01285 vecCol.resize( localSize ); 01286 vecS.resize( localSize ); 01287 01288 if( ncMap.is_valid() ) 01289 { 01290 varRow->set_cur( (long)( offsetRead ) ); 01291 varRow->get( &( vecRow[0] ), localSize ); 01292 01293 varCol->set_cur( (long)( offsetRead ) ); 01294 varCol->get( &( vecCol[0] ), localSize ); 01295 01296 varS->set_cur( (long)( offsetRead ) ); 01297 varS->get( &( vecS[0] ), localSize ); 01298 01299 ncMap.close(); 01300 } 01301 else 01302 { 01303 #ifdef MOAB_HAVE_PNETCDF 01304 // fill the local vectors with the variables from pnetcdf file; first inquire, then fill 01305 MPI_Offset start = (MPI_Offset)offsetRead; 01306 MPI_Offset count = (MPI_Offset)localSize; 01307 int varid; 01308 ret = ncmpi_inq_varid( ncfile, "S", &varid ); 01309 ERR_PARNC( ret ); 01310 ret = ncmpi_get_vara_double_all( ncfile, varid, &start, &count, &vecS[0] ); 01311 ERR_PARNC( ret ); 01312 ret = ncmpi_inq_varid( ncfile, "row", &varid ); 01313 ERR_PARNC( ret ); 01314 ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecRow[0] ); 01315 ERR_PARNC( ret ); 01316 ret = ncmpi_inq_varid( ncfile, "col", &varid ); 01317 ERR_PARNC( ret ); 01318 ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecCol[0] ); 01319 ERR_PARNC( ret ); 01320 ret = ncmpi_close( ncfile ); 01321 ERR_PARNC( ret ); 01322 #endif 01323 } 01324 01325 // Now let us set the necessary global-to-local ID maps so that A*x operations 01326 // can be performed cleanly as if map was computed online 01327 row_dtoc_dofmap.clear(); 01328 // row_dtoc_dofmap.reserve( nB / size ); 01329 col_dtoc_dofmap.clear(); 01330 rowMap.clear(); 01331 colMap.clear(); 01332 // col_dtoc_dofmap.reserve( 2 * nA / size ); 01333 // row_dtoc_dofmap.resize( m_nTotDofs_Dest, UINT_MAX ); 01334 // col_dtoc_dofmap.resize( m_nTotDofs_SrcCov, UINT_MAX ); 01335 01336 #ifdef MOAB_HAVE_MPI 01337 // bother with tuple list only if size > 1 01338 // otherwise, just fill the sparse matrix 01339 if( size > 1 ) 01340 { 01341 std::vector< int > ownership; 01342 // the default trivial partitioning scheme 01343 int nDofs = nB; // this is for row partitioning 01344 if( !row_partition ) nDofs = nA; // column partitioning 01345 01346 // assert(row_major_ownership == true); // this block is valid only for row-based partitioning 01347 ownership.resize( size ); 01348 int nPerPart = nDofs / size; 01349 int nRemainder = nDofs % size; // Keep the remainder in root 01350 ownership[0] = nPerPart + nRemainder; 01351 for( int ip = 1, roffset = ownership[0]; ip < size; ++ip ) 01352 { 01353 roffset += nPerPart; 01354 ownership[ip] = roffset; 01355 } 01356 moab::TupleList* tl = new moab::TupleList; 01357 unsigned numr = 1; // 01358 tl->initialize( 3, 0, 0, numr, localSize ); // to proc, row, col, value 01359 tl->enableWriteAccess(); 01360 // populate 01361 for( int i = 0; i < localSize; i++ ) 01362 { 01363 int rowval = vecRow[i] - 1; // dofs are 1 based in the file 01364 int colval = vecCol[i] - 1; 01365 int to_proc = -1; 01366 int dof_val = colval; 01367 if( row_partition ) dof_val = rowval; 01368 01369 if( ownership[0] > dof_val ) 01370 to_proc = 0; 01371 else 01372 { 01373 for( int ip = 1; ip < size; ++ip ) 01374 { 01375 if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val ) 01376 { 01377 to_proc = ip; 01378 break; 01379 } 01380 } 01381 } 01382 01383 int n = tl->get_n(); 01384 tl->vi_wr[3 * n] = to_proc; 01385 tl->vi_wr[3 * n + 1] = rowval; 01386 tl->vi_wr[3 * n + 2] = colval; 01387 tl->vr_wr[n] = vecS[i]; 01388 tl->inc_n(); 01389 } 01390 // heavy communication 01391 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl, 0 ); 01392 01393 if( owned_dof_ids.size() > 0 ) 01394 { 01395 // we need to send desired dof to the rendez_vous point 01396 moab::TupleList tl_re; // 01397 tl_re.initialize( 2, 0, 0, 0, owned_dof_ids.size() ); // to proc, value 01398 tl_re.enableWriteAccess(); 01399 // send first to rendez_vous point, decided by trivial partitioning 01400 01401 for( size_t i = 0; i < owned_dof_ids.size(); i++ ) 01402 { 01403 int to_proc = -1; 01404 int dof_val = owned_dof_ids[i] - 1; // dofs are 1 based in the file, partition from 0 ? 01405 01406 if( ownership[0] > dof_val ) 01407 to_proc = 0; 01408 else 01409 { 01410 for( int ip = 1; ip < size; ++ip ) 01411 { 01412 if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val ) 01413 { 01414 to_proc = ip; 01415 break; 01416 } 01417 } 01418 } 01419 01420 int n = tl_re.get_n(); 01421 tl_re.vi_wr[2 * n] = to_proc; 01422 tl_re.vi_wr[2 * n + 1] = dof_val; 01423 01424 tl_re.inc_n(); 01425 } 01426 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl_re, 0 ); 01427 // now we know in tl_re where do we need to send back dof_val 01428 moab::TupleList::buffer sort_buffer; 01429 sort_buffer.buffer_init( tl_re.get_n() ); 01430 tl_re.sort( 1, &sort_buffer ); // so now we order by value 01431 01432 sort_buffer.buffer_init( tl->get_n() ); 01433 int indexOrder = 2; // colVal 01434 if( row_partition ) indexOrder = 1; // rowVal 01435 //tl->sort( indexOrder, &sort_buffer ); 01436 01437 std::map< int, int > startDofIndex, endDofIndex; // indices in tl_re for values we want 01438 int dofVal = -1; 01439 if( tl_re.get_n() > 0 ) dofVal = tl_re.vi_rd[1]; // first dof val on this rank 01440 startDofIndex[dofVal] = 0; 01441 endDofIndex[dofVal] = 0; // start and end 01442 for( unsigned k = 1; k < tl_re.get_n(); k++ ) 01443 { 01444 int newDof = tl_re.vi_rd[2 * k + 1]; 01445 if( dofVal == newDof ) 01446 { 01447 endDofIndex[dofVal] = k; // increment by 1 actually 01448 } 01449 else 01450 { 01451 dofVal = newDof; 01452 startDofIndex[dofVal] = k; 01453 endDofIndex[dofVal] = k; 01454 } 01455 } 01456 01457 // basically, for each value we are interested in, index in tl_re with those values are 01458 // tl_re.vi_rd[2*startDofIndex+1] == valDof == tl_re.vi_rd[2*endDofIndex+1] 01459 // so now we have ordered 01460 // tl_re shows to what proc do we need to send the tuple (row, col, val) 01461 moab::TupleList* tl_back = new moab::TupleList; 01462 unsigned numr = 1; // 01463 // localSize is a good guess, but maybe it should be bigger ? 01464 // this could be bigger for repeated dofs 01465 tl_back->initialize( 3, 0, 0, numr, tl->get_n() ); // to proc, row, col, value 01466 tl_back->enableWriteAccess(); 01467 // now loop over tl and tl_re to see where to send 01468 // form the new tuple, which will contain the desired dofs per task, per row or column distribution 01469 01470 for( unsigned k = 0; k < tl->get_n(); k++ ) 01471 { 01472 int valDof = tl->vi_rd[3 * k + indexOrder]; // 1 for row, 2 for column // first value, it should be 01473 for( int ire = startDofIndex[valDof]; ire <= endDofIndex[valDof]; ire++ ) 01474 { 01475 int to_proc = tl_re.vi_rd[2 * ire]; 01476 int n = tl_back->get_n(); 01477 tl_back->vi_wr[3 * n] = to_proc; 01478 tl_back->vi_wr[3 * n + 1] = tl->vi_rd[3 * k + 1]; // row 01479 tl_back->vi_wr[3 * n + 2] = tl->vi_rd[3 * k + 2]; // col 01480 tl_back->vr_wr[n] = tl->vr_rd[k]; 01481 tl_back->inc_n(); 01482 } 01483 } 01484 01485 // now communicate to the desired tasks: 01486 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl_back, 0 ); 01487 01488 tl_re.reset(); // clear memory, although this will go out of scope 01489 tl->reset(); 01490 tl = tl_back; 01491 } 01492 01493 int rindexMax = 0, cindexMax = 0; 01494 // populate the sparsematrix, using rowMap and colMap 01495 int n = tl->get_n(); 01496 for( int i = 0; i < n; i++ ) 01497 { 01498 int rindex, cindex; 01499 const int& vecRowValue = tl->vi_wr[3 * i + 1]; 01500 const int& vecColValue = tl->vi_wr[3 * i + 2]; 01501 01502 std::map< int, int >::iterator riter = rowMap.find( vecRowValue ); 01503 if( riter == rowMap.end() ) 01504 { 01505 rowMap[vecRowValue] = rindexMax; 01506 rindex = rindexMax; 01507 row_gdofmap.push_back( vecRowValue ); 01508 // row_dtoc_dofmap.push_back( vecRowValue ); 01509 rindexMax++; 01510 } 01511 else 01512 rindex = riter->second; 01513 01514 std::map< int, int >::iterator citer = colMap.find( vecColValue ); 01515 if( citer == colMap.end() ) 01516 { 01517 colMap[vecColValue] = cindexMax; 01518 cindex = cindexMax; 01519 col_gdofmap.push_back( vecColValue ); 01520 // col_dtoc_dofmap.push_back( vecColValue ); 01521 cindexMax++; 01522 } 01523 else 01524 cindex = citer->second; 01525 01526 sparseMatrix( rindex, cindex ) = tl->vr_wr[i]; 01527 } 01528 tl->reset(); 01529 } 01530 else 01531 #endif 01532 { 01533 int rindexMax = 0, cindexMax = 0; 01534 01535 for( int i = 0; i < nS; i++ ) 01536 { 01537 int rindex, cindex; 01538 const int& vecRowValue = vecRow[i] - 1; // the rows, cols are 1 based in the file 01539 const int& vecColValue = vecCol[i] - 1; 01540 01541 std::map< int, int >::iterator riter = rowMap.find( vecRowValue ); 01542 if( riter == rowMap.end() ) 01543 { 01544 rowMap[vecRowValue] = rindexMax; 01545 rindex = rindexMax; 01546 row_gdofmap.push_back( vecRowValue ); 01547 // row_dtoc_dofmap.push_back( vecRowValue ); 01548 rindexMax++; 01549 } 01550 else 01551 rindex = riter->second; 01552 01553 std::map< int, int >::iterator citer = colMap.find( vecColValue ); 01554 if( citer == colMap.end() ) 01555 { 01556 colMap[vecColValue] = cindexMax; 01557 cindex = cindexMax; 01558 col_gdofmap.push_back( vecColValue ); 01559 // col_dtoc_dofmap.push_back( vecColValue ); 01560 cindexMax++; 01561 } 01562 else 01563 cindex = citer->second; 01564 01565 sparseMatrix( rindex, cindex ) = vecS[i]; 01566 } 01567 } 01568 01569 m_nTotDofs_SrcCov = sparseMatrix.GetColumns(); 01570 m_nTotDofs_Dest = sparseMatrix.GetRows(); 01571 01572 #ifdef MOAB_HAVE_EIGEN3 01573 this->copy_tempest_sparsemat_to_eigen3(); 01574 #endif 01575 01576 // Reset the source and target data first 01577 m_rowVector.setZero(); 01578 m_colVector.setZero(); 01579 01580 return moab::MB_SUCCESS; 01581 } 01582 01583 ///////////////////////////////////////////////////////////////////////////////