1- /* * @file heat-equation-coupling .cpp
1+ /* * @file partitioned- heat-conduction .cpp
22
33 @brief Heat equation participant for a double coupled heat equation
44
@@ -56,7 +56,7 @@ int main(int argc, char *argv[])
5656 gsConstantFunction<> f (beta-2 -2 *alpha,2 );
5757 gsFunctionExpr<> u_ex (" 1+x^2+" + std::to_string (alpha) + " *y^2 + " + std::to_string (beta) + " *" + std::to_string (time),2 );
5858
59- gsMultiBasis<> bases (patches);// true: poly-splines (not NURBS)
59+ gsMultiBasis<> bases (patches); // true: poly-splines (not NURBS)
6060
6161 bases.setDegree ( bases.maxCwiseDegree () + numElevate);
6262
@@ -90,38 +90,38 @@ int main(int argc, char *argv[])
9090 GISMO_ERROR (" Side unknown" );
9191
9292 patchSide couplingInterface (0 ,couplingSide);
93- typename gsBasis<real_t >::domainIter domIt = bases.basis (couplingInterface.patch ).makeDomainIterator (couplingInterface.side ());
93+ // Use STL-style domain iterators on the boundary side
94+ const gsBasis<real_t >& basisOnPatch = bases.basis (couplingInterface.patch );
95+ typename gsBasis<real_t >::domainIter domIt = basisOnPatch.domain ()->beginBdr (couplingInterface.side ());
96+ typename gsBasis<real_t >::domainIter domItEnd = basisOnPatch.domain ()->endBdr (couplingInterface.side ());
9497 index_t rows = patches.targetDim ();
9598 gsMatrix<> nodes;
9699 // Start iteration over elements
97100 gsVector<> tmp;
98101 index_t k=0 ;
99102
100103 gsOptionList quadOptions = A.options ();
101- // NEED A DIFFERENT RULE FOR dirichlet::interpolation --> see: gsGaussRule<T> bdQuRule(basis, 1.0, 1, iter->side().direction());
102- /*
103- quadOptions.addInt("quRule","Quadrature rule [1:GaussLegendre,2:GaussLobatto]",1);
104- quadOptions.addReal("quA","Number of quadrature points: quA*deg + quB",1.0);
105- quadOptions.addInt("quB","Number of quadrature points: quA*deg + quB",1);
106- */
104+ // Quadrature options can be customized via A.options()
107105
108106 index_t quadSize = 0 ;
109107 typename gsQuadRule<real_t >::uPtr QuRule; // Quadrature rule ---->OUT
110- for (; domIt-> good (); domIt-> next (), k++ )
108+ for (; domIt < domItEnd; ++ domIt, ++k )
111109 {
112- QuRule = gsQuadrature::getPtr (bases. basis (couplingInterface. patch ) , quadOptions,couplingInterface.side ().direction ());
113- quadSize+= QuRule->numNodes ();
110+ QuRule = gsQuadrature::getPtr (basisOnPatch , quadOptions, couplingInterface.side ().direction ());
111+ quadSize += QuRule->numNodes ();
114112 }
115113 gsMatrix<> uv (rows,quadSize); // Coordinates of the quadrature points in parameter space
116114 gsMatrix<> xy (rows,quadSize); // Coordinates of the quadrature points in physical space
117115
118116 index_t offset = 0 ;
119117
120- for (domIt->reset (); domIt->good (); domIt->next (), k++ )
118+ // Reset iterator and loop again to fill uv/xy
119+ domIt = basisOnPatch.domain ()->beginBdr (couplingInterface.side ());
120+ for (; domIt < domItEnd; ++domIt, ++k )
121121 {
122- QuRule = gsQuadrature::getPtr (bases. basis (couplingInterface. patch ) , quadOptions,couplingInterface.side ().direction ());
122+ QuRule = gsQuadrature::getPtr (basisOnPatch , quadOptions, couplingInterface.side ().direction ());
123123 // Map the Quadrature rule to the element
124- QuRule->mapTo ( domIt-> lowerCorner (), domIt-> upperCorner (),
124+ QuRule->mapTo ( domIt. lowerCorner (), domIt. upperCorner (),
125125 nodes, tmp);
126126 uv.block (0 ,offset,rows,QuRule->numNodes ()) = nodes;
127127
@@ -132,29 +132,61 @@ int main(int argc, char *argv[])
132132 }
133133
134134 std::string membername;
135- if (side==0 ) // left
135+ if (side==0 ) // left participant
136136 membername = " Dirichlet" ;
137- else if (side==1 ) // right
137+ else if (side==1 ) // right participant
138138 membername = " Neumann" ;
139139 else
140140 GISMO_ERROR (" Side unknown" );
141141
142+ // PreCICE participants and meshes per provided config
143+ // Dirichlet provides Dirichlet-Mesh, reads Temperature on Dirichlet-Mesh, writes Heat-Flux on Neumann-Mesh
144+ // Neumann provides Neumann-Mesh, reads Heat-Flux on Neumann-Mesh, writes Temperature on Dirichlet-Mesh
145+ const std::string localMeshName = membername + " -Mesh" ;
146+ const std::string remoteMeshName = (membername==" Dirichlet" ) ? std::string (" Neumann-Mesh" ) : std::string (" Dirichlet-Mesh" );
147+ const std::string tempName = " Temperature" ;
148+ const std::string fluxName = " Heat-Flux" ;
149+
142150 gsPreCICE<real_t > interface (membername, precice_config);
143- std::string meshName = membername + " -Mesh" ;
144- interface.addMesh (meshName,xy);
151+ // Register local mesh coordinates
152+ interface.addMesh (localMeshName, xy);
153+
154+ // Define access region for the received mesh in serial mode
155+ // Use a generous bounding box pattern seen in other examples
156+ {
157+ gsMatrix<> bbox (rows, 2 );
158+ bbox.col (0 ).setConstant (-1e300 );
159+ bbox.col (1 ).setConstant ( 1e300 );
160+ bbox.transposeInPlace ();
161+ bbox.resize (1 , bbox.rows () * bbox.cols ());
162+ interface.setMeshAccessRegion (remoteMeshName, bbox);
163+ }
145164
146165 interface.requiresInitialData ();
147166
148167 real_t precice_dt = interface.initialize ();
149168
150- std::string tempName = " Temperature" ;
151- std::string fluxName = " Heat-Flux" ;
169+ // Direct-access: fetch partner mesh vertex IDs and coordinates.
170+ // Evaluate quantities at partner coordinates (no reordering needed).
171+ gsVector<index_t > remoteIDs;
172+ gsMatrix<> remoteCoords;
173+ interface.getMeshVertexIDsAndCoordinates (remoteMeshName, remoteIDs, remoteCoords);
174+ // Invert partner physical coords to param coords on our coupling patch
175+ gsMatrix<> uvRemote;
176+ patches.patch (couplingInterface.patch ).invertPoints (remoteCoords, uvRemote, 1e-10 );
177+ // Ensure boundary parameter is exact for evalBdr
178+ const int bdir = couplingInterface.side ().direction ();
179+ const real_t bpar = couplingInterface.side ().parameter ();
180+ for (index_t i = 0 ; i != uvRemote.cols (); ++i)
181+ uvRemote (bdir, i) = bpar;
152182
153183// ----------------------------------------------------------------------------------------------
154184
155185 gsBoundaryConditions<> bcInfo;
156- gsPreCICEFunction<real_t > g_CD (&interface,meshName,(side==0 ? tempName : fluxName),patches,1 );
157- gsPreCICEFunction<real_t > g_CN (&interface,meshName,(side==0 ? tempName : fluxName),patches,1 );
186+ // Read functions according to participant role and config
187+ // Dirichlet reads Temperature on Dirichlet-Mesh; Neumann reads Heat-Flux on Neumann-Mesh
188+ gsPreCICEFunction<real_t > g_CD (&interface, (membername==" Dirichlet" ? localMeshName : remoteMeshName), tempName, patches, 1 );
189+ gsPreCICEFunction<real_t > g_CN (&interface, (membername==" Neumann" ? localMeshName : remoteMeshName), fluxName, patches, 1 );
158190 gsFunction<> * g_C = &u_ex;
159191
160192 bcInfo.addCondition (0 , boundary::south, condition_type::dirichlet, &u_ex, 0 , false , 0 );
@@ -188,13 +220,11 @@ int main(int argc, char *argv[])
188220 auto ff = A.getCoeff (f, G);
189221
190222 // Set the solution
191- gsMatrix<> solVector, solVector_ini ;
223+ gsMatrix<> solVector;
192224 solution u_sol = A.getSolution (u, solVector);
193- solution u_ini = A.getSolution (u, solVector);
194225
195226 u.setup (bcInfo, dirichlet::homogeneous, 0 );
196227 A.initSystem ();
197- gsDebugVar (A.numDofs ());
198228 A.assemble ( u * u.tr () * meas (G));
199229 gsSparseMatrix<> M = A.matrix ();
200230
@@ -211,18 +241,17 @@ int main(int argc, char *argv[])
211241 A.initSystem ();
212242 A.assemble ( u * u.tr () * meas (G), u * uex * meas (G) );
213243 solver.compute (A.matrix ());
214- solVector_ini = solVector = solver.solve (A.rhs ());
215-
216- gsMatrix<> result (1 ,uv.cols ()), tmp2;
244+ solVector = solver.solve (A.rhs ());
245+ gsMatrix<> result (1 ,uv.cols ()), tmp2;
217246 // Write initial data
218247 if (interface.requiresWritingCheckpoint ())
219248 {
220249 for (index_t k=0 ; k!=uv.cols (); k++)
221250 {
222251 if (side==0 )
223252 {
224- gsWarn<< " Write the flux here!!! \n " ;
225- tmp2 = ev.eval ( - jac ( u_sol) * nv (G).normalized (), uv.col (k));
253+ // Normal heat flux q_n = -k * grad(u) · n on the coupling boundary
254+ tmp2 = ev.evalBdr ( - k_temp * ( igrad ( u_sol, G ) * nv (G).normalized ()), uv.col (k), couplingInterface );
226255 result (0 ,k) = tmp2.at (0 );
227256 }
228257 else
@@ -231,18 +260,28 @@ int main(int argc, char *argv[])
231260 result (0 ,k) = tmp2.at (0 );
232261 }
233262 }
234- gsDebugVar (result);
235- interface.writeData (meshName,side==0 ? fluxName : tempName,xy,result);
263+ // Build values at partner coordinates (order matches remoteIDs)
264+ result.resize (1 , uvRemote.cols ());
265+ for (index_t k=0 ; k!=uvRemote.cols (); ++k)
266+ {
267+ if (side==0 ) // Dirichlet writes flux
268+ {
269+ tmp2 = ev.evalBdr ( - k_temp * (igrad (u_sol, G) * nv (G).normalized ()), uvRemote.col (k), couplingInterface);
270+ result (0 ,k) = tmp2.at (0 );
271+ }
272+ else // Neumann writes temperature
273+ {
274+ tmp2 = ev.evalBdr (u_sol, uvRemote.col (k), couplingInterface);
275+ result (0 ,k) = tmp2.at (0 );
276+ }
277+ }
278+ // Write on partner mesh using its vertex IDs (direct-access config)
279+ interface.writeData (remoteMeshName, (side==0 ? fluxName : tempName), remoteIDs, result);
236280 }
237- // interface.initialize_data();
238-
239- // interface.readBlockScalarData(meshName,side==0 ? tempName : fluxName,xy,result);
240- // gsDebugVar(result);
241281
242282 // Initialize the RHS for assembly
243283 if (side==0 )
244284 g_C = &g_CD;
245- gsDebugVar (bcInfo);
246285 A.initSystem ();
247286 A.assemble ( k_temp * igrad (u, G) * igrad (u, G).tr () * meas (G), u * uex * meas (G) );
248287 gsSparseMatrix<> K = A.matrix ();
@@ -253,33 +292,37 @@ int main(int argc, char *argv[])
253292 gsVector<> F_checkpoint = F;
254293 gsMatrix<> solVector_checkpoint = solVector;
255294
256- gsParaviewCollection collection (" solution " );
257- gsParaviewCollection exact_collection (" exact_solution " );
295+ gsParaviewCollection collection (membername + " _solution " );
296+ gsParaviewCollection exact_collection (membername + " _exact_solution " );
258297
259298 index_t timestep = 0 ;
260299 index_t timestep_checkpoint = 0 ;
261300 real_t t_checkpoint = 0 ;
262301 if (plot)
263302 {
264- std::string fileName = " solution_ " + util::to_string (timestep);
303+ std::string fileName = membername + " _solution_ " + util::to_string (timestep);
265304 ev.options ().setSwitch (" plot.elements" , true );
266305 ev.options ().setInt (" plot.npts" , 1000 );
267306 ev.writeParaview ( u_sol , G, fileName);
268307 for (size_t p=0 ; p!=patches.nPatches (); p++)
269308 {
270- fileName = " solution_ " + util::to_string (timestep) + std::to_string (p);
309+ fileName = membername + " _solution_ " + util::to_string (timestep) + std::to_string (p);
271310 collection.addTimestep (fileName,time," .vts" );
272311 }
273312
274- // fileName = "exact_solution_" + util::to_string(timestep);
275- // ev.writeParaview( uex , G, fileName);
276- // for (size_t p=0; p!=patches.nPatches(); p++)
277- // {
278- // fileName = "exact_solution_" + util::to_string(timestep) + std::to_string(p);
279- // exact_collection.addTimestep(fileName,time,".vts");
280- // }
313+ // write exact solution at initial time
314+ fileName = membername + " _exact_solution_" + util::to_string (timestep);
315+ {
316+ auto uex_coeff = A.getCoeff (u_ex, G);
317+ ev.writeParaview ( uex_coeff , G, fileName);
318+ }
319+ for (size_t p=0 ; p!=patches.nPatches (); p++)
320+ {
321+ std::string fileName2 = membername + " _exact_solution_" + util::to_string (timestep) + std::to_string (p);
322+ exact_collection.addTimestep (fileName2,time," .vts" );
323+ }
281324
282- ev.writeParaview ( u_sol , G, " initial_solution " );
325+ ev.writeParaview ( u_sol , G, membername + " _initial_solution " );
283326
284327 }
285328
@@ -300,7 +343,6 @@ int main(int argc, char *argv[])
300343 // save checkpoint
301344 if (interface.requiresWritingCheckpoint ())
302345 {
303- gsDebugVar (" Write checkpoint" );
304346 F_checkpoint = F0;
305347 t_checkpoint = time;
306348 timestep_checkpoint = timestep;
@@ -318,16 +360,10 @@ int main(int argc, char *argv[])
318360 gsMatrix<> result (1 ,uv.cols ()), tmp;
319361 for (index_t k=0 ; k!=uv.cols (); k++)
320362 {
321- // gsDebugVar(ev.eval(nv(G),uv.col(k)));
322- // tmp = ev.eval(k_temp * igrad(u_sol,G),uv.col(k));
323- // Only exchange y component
324- // result(0,k) = -tmp.at(1);
325- //
326- //
327363 if (side==0 )
328364 {
329- gsWarn<< " Write the flux here!!! \n " ;
330- tmp = ev.eval ( jac ( u_sol) * nv (G).normalized (), uv.col (k));
365+ // Normal heat flux q_n = -k * grad(u) · n on the coupling boundary
366+ tmp = ev.evalBdr ( - k_temp * ( igrad ( u_sol, G ) * nv (G).normalized ()), uv.col (k), couplingInterface );
331367 result (0 ,k) = tmp.at (0 );
332368 }
333369 else
@@ -336,7 +372,23 @@ int main(int argc, char *argv[])
336372 result (0 ,k) = tmp.at (0 );
337373 }
338374 }
339- interface.writeData (meshName,side==0 ? fluxName : tempName,xy,result);
375+ // Build values at partner coordinates (order matches remoteIDs)
376+ result.resize (1 , uvRemote.cols ());
377+ for (index_t k=0 ; k!=uvRemote.cols (); ++k)
378+ {
379+ if (side==0 ) // Dirichlet writes flux
380+ {
381+ tmp = ev.evalBdr ( - k_temp * (igrad (u_sol, G) * nv (G).normalized ()), uvRemote.col (k), couplingInterface);
382+ result (0 ,k) = tmp.at (0 );
383+ }
384+ else // Neumann writes temperature
385+ {
386+ tmp = ev.evalBdr (u_sol, uvRemote.col (k), couplingInterface);
387+ result (0 ,k) = tmp.at (0 );
388+ }
389+ }
390+ // Write on partner mesh using its vertex IDs (direct-access config)
391+ interface.writeData (remoteMeshName, (side==0 ? fluxName : tempName), remoteIDs, result);
340392
341393 // do the coupling
342394 precice_dt = interface.advance (dt);
@@ -348,7 +400,6 @@ int main(int argc, char *argv[])
348400
349401 if (interface.requiresReadingCheckpoint ())
350402 {
351- gsDebugVar (" Read checkpoint" );
352403 F0 = F_checkpoint;
353404 time = t_checkpoint;
354405 timestep = timestep_checkpoint;
@@ -358,15 +409,27 @@ int main(int argc, char *argv[])
358409 {
359410 if (timestep % plotmod==0 && plot)
360411 {
361- std::string fileName = " solution_ " + util::to_string (timestep);
412+ std::string fileName = membername + " _solution_ " + util::to_string (timestep);
362413 ev.options ().setSwitch (" plot.elements" , true );
363414 ev.options ().setInt (" plot.npts" , 1000 );
364415 ev.writeParaview ( u_sol , G, fileName);
365416 for (size_t p=0 ; p!=patches.nPatches (); p++)
366417 {
367- fileName = " solution_ " + util::to_string (timestep) + std::to_string (p);
418+ fileName = membername + " _solution_ " + util::to_string (timestep) + std::to_string (p);
368419 collection.addTimestep (fileName,time," .vts" );
369420 }
421+
422+ // write exact solution at current time
423+ std::string fileNameExact = membername + " _exact_solution_" + util::to_string (timestep);
424+ {
425+ auto uex_coeff = A.getCoeff (u_ex, G);
426+ ev.writeParaview ( uex_coeff , G, fileNameExact);
427+ }
428+ for (size_t p=0 ; p!=patches.nPatches (); p++)
429+ {
430+ std::string fileName2 = membername + " _exact_solution_" + util::to_string (timestep) + std::to_string (p);
431+ exact_collection.addTimestep (fileName2,time," .vts" );
432+ }
370433 }
371434 }
372435 }
0 commit comments