Skip to content

Commit e557b51

Browse files
Update the partitioned heat conduction example for direct mesh access
1 parent da3f55e commit e557b51

File tree

2 files changed

+147
-105
lines changed

2 files changed

+147
-105
lines changed

examples/partitioned-heat-conduction.cpp

Lines changed: 126 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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

Comments
 (0)