@@ -102,46 +102,31 @@ class Integral:
102102 raise RuntimeError (" Integral evaluation for Dyadic integrands not supported." )
103103
104104
105- # BUGFIX(#171): clone the mesh DM and create a fresh DS per call,
106- # rather than mutating the shared mesh DS. The previous code path
107- # was:
108- # ds = self.mesh.dm.getDS() # shared DS
109- # PetscDSSetObjective(ds, 0, fn) # mutate it
110- # DMPlexComputeIntegralFEM(...)
111- # PetscDSSetObjective on the shared DS makes
112- # DMPlexComputeIntegralFEM cost grow linearly with repeated
113- # evaluate() calls in long simulations — observed in convection
114- # diagnostics where t_vol grew from 5 s to 833 s over ~3000 calls.
115- # The sister class CellWiseIntegral already takes the
116- # clone-DM + createDS path; this brings Integral in line.
117- # Explicit destroy of the clone at the end keeps long runs bounded.
118- mesh = self .mesh
105+ self .dm = self .mesh.dm # .clone()
106+ mesh= self .mesh
119107
120108 _getext_result = getext(self .mesh, JITCallbackSet(residual = (self .fn,)),
121109 self .mesh.vars.values(), verbose = verbose)
122110 cdef PtrContainer ext = _getext_result.ptrobj
123111
124112 # Pull out vec for variables, and go ahead with the integral
113+
125114 self .mesh.update_lvec()
126- a_global = self .mesh. dm.getGlobalVec()
127- self .mesh. dm.localToGlobal(self .mesh.lvec, a_global)
115+ a_global = self .dm.getGlobalVec()
116+ self .dm.localToGlobal(self .mesh.lvec, a_global)
128117
129118 cdef Vec cgvec
130119 cgvec = a_global
131120
132- cdef DM dmc = self .mesh.dm.clone()
133- cdef FE fec = FE().createDefault(self .mesh.dim, 1 , False , - 1 )
134- dmc.setField(0 , fec)
135- dmc.createDS()
136-
137- cdef DS ds = dmc.getDS()
121+ cdef DM dm = self .dm
122+ cdef DS ds = self .dm.getDS()
138123 cdef PetscScalar val_array[256 ]
139124
125+ # Now set callback...
140126 ierr = PetscDSSetObjective(ds.ds, 0 , ext.fns_residual[0 ]); CHKERRQ(ierr)
141- ierr = DMPlexComputeIntegralFEM(dmc .dm, cgvec.vec, & (val_array[0 ]), NULL ); CHKERRQ(ierr)
127+ ierr = DMPlexComputeIntegralFEM(dm .dm, cgvec.vec, & (val_array[0 ]), NULL ); CHKERRQ(ierr)
142128
143- self .mesh.dm.restoreGlobalVec(a_global)
144- dmc.destroy()
129+ self .dm.restoreGlobalVec(a_global)
145130
146131 # We're making an assumption here that PetscScalar is same as double.
147132 # Need to check where this may not be the case.
@@ -315,10 +300,15 @@ class CellWiseIntegral:
315300 cdef Vec cgvec
316301 cgvec = a_global
317302
318- # # Does this need to be consistent with everything else ?
319-
303+ # TODO(BUG): clone+createDefault+createDS gives dmc a single P1 field,
304+ # but cgvec is packed for mesh.dm's multi-field layout — the integral
305+ # reads the wrong DOFs and over-counts by ~2x on the unit square.
306+ # Same bug as PR #172 (reverted in PR #173-followup). Tests in
307+ # tests/test_0501_integrals.py::test_cellwise_integrate_* are xfail
308+ # until this is rewritten to integrate against mesh.dm + getDS()
309+ # directly (the pre-PR-172 Integral pattern).
320310 cdef DM dmc = self .mesh.dm.clone()
321- cdef FE fec = FE().createDefault(self .dim, 1 , False , - 1 )
311+ cdef FE fec = FE().createDefault(self .mesh. dim, 1 , False , - 1 )
322312 dmc.setField(0 , fec)
323313 dmc.createDS()
324314
0 commit comments