@@ -208,7 +208,7 @@ def cluster(obj: object, clevel: ClusterLevel) -> Any:
208208
209209
210210@cluster .register (IndexList )
211- def _cluster_index_list (obj : IndexList , clevel : ClusterLevel ) -> IndexList :
211+ def cluster_index_list (obj : IndexList , clevel : ClusterLevel ) -> IndexList :
212212 assert obj .nclusters == clevel .nclusters
213213
214214 if clevel .nclusters == 1 :
@@ -224,7 +224,7 @@ def _cluster_index_list(obj: IndexList, clevel: ClusterLevel) -> IndexList:
224224
225225
226226@cluster .register (TargetAndSourceClusterList )
227- def _cluster_target_and_source_cluster_list (
227+ def cluster_target_and_source_cluster_list (
228228 obj : TargetAndSourceClusterList , clevel : ClusterLevel ,
229229 ) -> TargetAndSourceClusterList :
230230 assert obj .nclusters == clevel .nclusters
@@ -238,7 +238,7 @@ def _cluster_target_and_source_cluster_list(
238238
239239
240240@cluster .register (np .ndarray )
241- def _cluster_ndarray (obj : NDArray [Any ], clevel : ClusterLevel ) -> NDArray [Any ]:
241+ def cluster_ndarray (obj : NDArray [Any ], clevel : ClusterLevel ) -> NDArray [Any ]:
242242 assert obj .shape == (clevel .nclusters ,)
243243 if clevel .nclusters == 1 :
244244 return obj
@@ -420,26 +420,14 @@ def partition_by_nodes(
420420
421421# {{{ visualize clusters
422422
423- def visualize_clusters (actx : PyOpenCLArrayContext ,
424- generator : ProxyGenerator ,
425- srcindex : IndexList ,
426- tree : ClusterTree ,
427- filename : str | pathlib .Path , * ,
428- dofdesc : sym .DOFDescriptorLike = None ,
429- overwrite : bool = False ) -> None :
430- filename = pathlib .Path (filename )
431-
432- places = generator .places
433- if dofdesc is None :
434- dofdesc = places .auto_source
435- dofdesc = sym .as_dofdesc (dofdesc )
436-
437- discr = places .get_discretization (dofdesc .geometry , dofdesc .discr_stage )
438- assert isinstance (discr , Discretization )
439-
440- if discr .ambient_dim != 2 :
441- raise NotImplementedError (f"Unsupported dimension: { discr .ambient_dim } " )
442-
423+ def _visualize_clusters_2d (actx : PyOpenCLArrayContext ,
424+ discr : Discretization ,
425+ generator : ProxyGenerator ,
426+ srcindex : IndexList ,
427+ tree : ClusterTree ,
428+ filename : pathlib .Path , * ,
429+ dofdesc : sym .DOFDescriptor ,
430+ overwrite : bool = False ) -> None :
443431 import matplotlib .pyplot as pt
444432
445433 from arraycontext import flatten
@@ -448,7 +436,7 @@ def visualize_clusters(actx: PyOpenCLArrayContext,
448436
449437 x , y = actx .to_numpy (flatten (discr .nodes (), actx , leaf_class = DOFArray ))
450438 for clevel in tree .levels :
451- outfile = filename .with_stem (f"{ filename .stem } -{ clevel .level :03d} " )
439+ outfile = filename .with_stem (f"{ filename .stem } -lvl { clevel .level :03d} " )
452440 if not overwrite and outfile .exists ():
453441 raise FileExistsError (f"Output file '{ outfile } ' already exists" )
454442
@@ -493,6 +481,102 @@ def visualize_clusters(actx: PyOpenCLArrayContext,
493481
494482 srcindex = cluster (srcindex , clevel )
495483
484+
485+ def _visualize_clusters_3d (actx : PyOpenCLArrayContext ,
486+ discr : Discretization ,
487+ generator : ProxyGenerator ,
488+ srcindex : IndexList ,
489+ tree : ClusterTree ,
490+ filename : pathlib .Path , * ,
491+ dofdesc : sym .DOFDescriptor ,
492+ overwrite : bool = False ) -> None :
493+ from arraycontext import unflatten
494+ from meshmode .discretization .visualization import make_visualizer
495+
496+ for clevel in tree .levels :
497+ outfile = filename .with_stem (f"{ filename .stem } -lvl{ clevel .level :03d} " )
498+ outfile = outfile .with_suffix (".vtu" )
499+ if not overwrite and outfile .exists ():
500+ raise FileExistsError (f"Output file '{ outfile } ' already exists" )
501+
502+ # construct proxy balls
503+ pxy = generator (actx , dofdesc , srcindex ).to_numpy (actx )
504+ pxycenters = pxy .centers
505+ pxyradii = pxy .radii
506+ nclusters = srcindex .nclusters
507+
508+ # construct meshes for each proxy ball
509+ from meshmode .mesh .generation import generate_sphere
510+ from meshmode .mesh .processing import affine_map , merge_disjoint_meshes
511+
512+ ref_mesh = generate_sphere (1 , 4 , uniform_refinement_rounds = 1 )
513+ pxymeshes = [
514+ affine_map (ref_mesh , A = pxyradii [i ], b = pxycenters [:, i ].squeeze ())
515+ for i in range (nclusters )
516+ ]
517+
518+ # merge meshes into a single discretization
519+ from meshmode .discretization .poly_element import (
520+ InterpolatoryEdgeClusteredGroupFactory ,
521+ )
522+ pxymesh = merge_disjoint_meshes ([discr .mesh , * pxymeshes ])
523+ pxydiscr = Discretization (actx , pxymesh ,
524+ InterpolatoryEdgeClusteredGroupFactory (4 ))
525+
526+ # add a marker field for all clusters
527+ marker = np .full ((pxydiscr .ndofs ,), np .nan , dtype = np .float64 )
528+ template_ary = actx .thaw (pxydiscr .nodes ()[0 ])
529+
530+ for i in range (srcindex .nclusters ):
531+ isrc = srcindex .cluster_indices (i )
532+ marker [isrc ] = 10.0 * (i + 1.0 )
533+ marker_dev = unflatten (template_ary , actx .from_numpy (marker ), actx )
534+
535+ # add a marker field for all proxies
536+ pxymarker = np .full ((pxydiscr .ndofs ,), np .nan , dtype = np .float64 )
537+ pxymarker [discr .ndofs :] = 1.0
538+ pxymarker_dev = unflatten (template_ary , actx .from_numpy (pxymarker ), actx )
539+
540+ # write it all out
541+ vis = make_visualizer (actx , pxydiscr )
542+ vis .write_vtk_file (outfile , [
543+ ("marker" , marker_dev ),
544+ ("proxies" , pxymarker_dev ),
545+ ], overwrite = overwrite )
546+
547+ srcindex = cluster (srcindex , clevel )
548+
549+
550+ def visualize_clusters (actx : PyOpenCLArrayContext ,
551+ generator : ProxyGenerator ,
552+ srcindex : IndexList ,
553+ tree : ClusterTree ,
554+ filename : str | pathlib .Path , * ,
555+ dofdesc : sym .DOFDescriptorLike = None ,
556+ overwrite : bool = False ) -> None :
557+ filename = pathlib .Path (filename )
558+
559+ places = generator .places
560+ if dofdesc is None :
561+ dofdesc = places .auto_source
562+ dofdesc = sym .as_dofdesc (dofdesc )
563+
564+ discr = places .get_discretization (dofdesc .geometry , dofdesc .discr_stage )
565+ assert isinstance (discr , Discretization )
566+
567+ if discr .ambient_dim == 2 :
568+ _visualize_clusters_2d (
569+ actx , discr , generator , srcindex , tree , filename ,
570+ dofdesc = dofdesc ,
571+ overwrite = overwrite )
572+ elif discr .ambient_dim == 3 :
573+ _visualize_clusters_3d (
574+ actx , discr , generator , srcindex , tree , filename ,
575+ dofdesc = dofdesc ,
576+ overwrite = overwrite )
577+ else :
578+ raise NotImplementedError (f"Unsupported dimension: { discr .ambient_dim } " )
579+
496580# }}}
497581
498582
0 commit comments