Skip to content

Commit 676fb43

Browse files
authored
Merge pull request #28 from danlipsa/optimize
Optimize
2 parents f00423c + 88a4c49 commit 676fb43

File tree

3 files changed

+209
-54
lines changed

3 files changed

+209
-54
lines changed

src/e3sm_quickview/pipeline.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,11 @@ def Update(self, data_file, conn_file, force_reload=False):
209209
)
210210

211211
# Step 1: Extract and transform atmospheric data
212-
atmos_extract = EAMTransformAndExtract( # noqa: F821
213-
registrationName="AtmosExtract", Input=self.data
212+
atmos_center = EAMCenterMeridian(
213+
registrationName="AtmosCenter", Input=self.data
214+
)
215+
atmos_extract = EAMExtract( # noqa: F821
216+
registrationName="AtmosExtract", Input=atmos_center
214217
)
215218
atmos_extract.LongitudeRange = [-180.0, 180.0]
216219
atmos_extract.LatitudeRange = [-90.0, 90.0]
@@ -224,7 +227,11 @@ def Update(self, data_file, conn_file, force_reload=False):
224227
atmos_proj.Projection = self.projection
225228
atmos_proj.Translate = 0
226229
atmos_proj.UpdatePipeline()
227-
self.moveextents = atmos_proj.GetDataInformation().GetBounds()
230+
231+
atmos_polydata = ExtractSurface(
232+
registrationName="AtmosPolyData", Input=atmos_proj
233+
)
234+
self.moveextents = atmos_polydata.GetDataInformation().GetBounds()
228235

229236
# Step 3: Load and process continent outlines
230237
if self.globe is None:
@@ -270,7 +277,7 @@ def Update(self, data_file, conn_file, force_reload=False):
270277
grid_proj.UpdatePipeline()
271278

272279
# Step 8: Cache all projected views for rendering
273-
self.views["atmosphere_data"] = OutputPort(atmos_proj, 0)
280+
self.views["atmosphere_data"] = OutputPort(atmos_polydata, 0)
274281
self.views["continents"] = OutputPort(cont_proj, 0)
275282
self.views["grid_lines"] = OutputPort(grid_proj, 0)
276283

src/e3sm_quickview/plugins/eam_projection.py

Lines changed: 172 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
from paraview.simple import *
22
from paraview.util.vtkAlgorithm import *
33
from vtkmodules.numpy_interface import dataset_adapter as dsa
4-
from vtkmodules.vtkCommonCore import vtkPoints
4+
from vtkmodules.vtkCommonCore import (
5+
vtkPoints,
6+
vtkIdList,
7+
)
58
from vtkmodules.vtkCommonDataModel import (
69
vtkPolyData,
710
vtkCellArray,
811
vtkPlane,
912
)
1013
from vtkmodules.vtkCommonTransforms import vtkTransform
11-
from vtkmodules.vtkFiltersCore import vtkAppendFilter
14+
from vtkmodules.vtkFiltersCore import (
15+
vtkAppendFilter,
16+
vtkGenerateIds,
17+
)
1218
from vtkmodules.vtkFiltersGeneral import (
1319
vtkTransformFilter,
1420
vtkTableBasedClipDataSet,
@@ -52,7 +58,6 @@ def ProcessPoint(point, radius):
5258
z = rho * math.cos(math.radians(phi))
5359
return [x, y, z]
5460

55-
5661
@smproxy.filter()
5762
@smproperty.input(name="Input")
5863
@smdomain.datatype(
@@ -408,74 +413,192 @@ def RequestData(self, request, inInfo, outInfo):
408413
@smproxy.filter()
409414
@smproperty.input(name="Input")
410415
@smdomain.datatype(
411-
dataTypes=["vtkPolyData", "vtkUnstructuredGrid"], composite_data_supported=False
416+
dataTypes=["vtkPolyData"], composite_data_supported=False
412417
)
413418
@smproperty.xml(
414419
"""
415-
<IntVectorProperty name="Center Meridian"
416-
command="SetCentralMeridian"
417-
number_of_elements="1"
418-
default_values="0">
419-
</IntVectorProperty>
420+
<DoubleVectorProperty name="Longitude Range"
421+
command="SetLongitudeRange"
422+
number_of_elements="2"
423+
default_values="-180 180">
424+
</DoubleVectorProperty>
425+
<DoubleVectorProperty name="Latitude Range"
426+
command="SetLatitudeRange"
427+
number_of_elements="2"
428+
default_values="-90 90">
429+
</DoubleVectorProperty>
420430
"""
421431
)
422-
class EAMCenterMeridian(VTKPythonAlgorithmBase):
432+
class EAMExtract(VTKPythonAlgorithmBase):
423433
def __init__(self):
424434
super().__init__(
425435
nInputPorts=1, nOutputPorts=1, outputType="vtkUnstructuredGrid"
426436
)
427-
self.project = 0
428-
self.cmeridian = 0.0
437+
self.longrange = [-180.0, 180.0]
438+
self.latrange = [-90.0, 90.0]
429439

430-
def SetCentralMeridian(self, meridian):
431-
if self.cmeridian != meridian:
432-
self.cmeridian = meridian
440+
def SetLongitudeRange(self, min, max):
441+
if self.longrange[0] != min or self.longrange[1] != max:
442+
self.longrange = [min, max]
443+
self.Modified()
444+
445+
def SetLatitudeRange(self, min, max):
446+
if self.latrange[0] != min or self.latrange[1] != max:
447+
self.latrange = [min, max]
433448
self.Modified()
434449

435450
def RequestData(self, request, inInfo, outInfo):
436451
inData = self.GetInputData(inInfo, 0, 0)
437452
outData = self.GetOutputData(outInfo, 0)
438-
439-
if self.cmeridian == 0:
453+
if self.longrange == [-180.0, 180] and self.latrange == [-90, 90]:
440454
outData.ShallowCopy(inData)
441455
return 1
442456

443-
split = (self.cmeridian - 180) if self.cmeridian > 0 else (self.cmeridian + 180)
457+
box = vtkPVBox()
458+
box.SetReferenceBounds(
459+
self.longrange[0],
460+
self.longrange[1],
461+
self.latrange[0],
462+
self.latrange[1],
463+
-1.0,
464+
1.0,
465+
)
466+
box.SetUseReferenceBounds(True)
467+
extract = vtkPVClipDataSet()
468+
extract.SetClipFunction(box)
469+
extract.InsideOutOn()
470+
extract.ExactBoxClipOn()
471+
extract.SetInputData(inData)
472+
extract.Update()
444473

445-
planeL = vtkPlane()
446-
planeL.SetOrigin([split, 0.0, 0.0])
447-
planeL.SetNormal([-1, 0, 0])
448-
clipL = vtkTableBasedClipDataSet()
449-
clipL.SetClipFunction(planeL)
450-
clipL.SetInputData(inData)
451-
clipL.Update()
474+
outData.ShallowCopy(extract.GetOutput())
475+
return 1
452476

453-
planeR = vtkPlane()
454-
planeR.SetOrigin([split, 0.0, 0.0])
455-
planeR.SetNormal([1, 0, 0])
456-
clipR = vtkTableBasedClipDataSet()
457-
clipR.SetClipFunction(planeR)
458-
clipR.SetInputData(inData)
459-
clipR.Update()
460477

461-
transFunc = vtkTransform()
462-
transFunc.Translate(360, 0, 0)
463-
transform = vtkTransformFilter()
464-
transform.SetInputData(clipL.GetOutput())
465-
transform.SetTransform(transFunc)
466-
transform.Update()
467478

468-
append = vtkAppendFilter()
469-
append.AddInputData(clipR.GetOutput())
470-
append.AddInputData(transform.GetOutput())
471-
append.Update()
479+
@smproxy.filter()
480+
@smproperty.input(name="Input")
481+
@smproperty.xml(
482+
"""
483+
<IntVectorProperty name="Meridian"
484+
command="SetMeridian"
485+
number_of_elements="1"
486+
default_values="0">
487+
<IntRangeDomain min="-180" max="180" name="range" />
488+
<Documentation>
489+
Sets the central meridian.
490+
Commonly used central meridians (longitudes) (- represents West, + represents East,
491+
0 is Greenwitch prime meridian):
492+
- 0 (Prime Meridian): Standard "Western" view.
493+
- -90/-100: Centered on North America.
494+
- 100/110: Centered on Asia.
495+
- -150/-160: Centered on the Pacific Ocean.
496+
- 20: Often used to center Europe and Africa.
497+
</Documentation>
498+
</IntVectorProperty>
499+
"""
500+
)
501+
@smdomain.datatype(
502+
dataTypes=["vtkPolyData", "vtkUnstructuredGrid"], composite_data_supported=False
503+
)
504+
class EAMCenterMeridian(VTKPythonAlgorithmBase):
505+
'''Cuts an unstructured grid and re-arranges the pieces such that
506+
the specified meridian is in the middle. Note that the mesh is
507+
specified with bounds [0, 360], but the meridian is specified in the more
508+
common bounds [-180, 180].
509+
'''
510+
def __init__(self):
511+
super().__init__(
512+
nInputPorts=1, nOutputPorts=1, outputType="vtkUnstructuredGrid"
513+
)
514+
# common values:
515+
self._center_meridian = 0
516+
self._cached_output = None
517+
518+
def SetMeridian(self, meridian_):
519+
'''
520+
Specifies the central meridian (longitude in the middle of the map)
521+
'''
522+
if meridian_ < -180 or meridian_ > 180:
523+
print_error("SetMeridian called with parameter outside [-180, 180]: {}".format(meridian_))
524+
return
525+
self._center_meridian = meridian_
526+
self.Modified()
472527

473-
transFunc = vtkTransform()
474-
transFunc.Translate(-(180 + split), 0, 0)
475-
transform = vtkTransformFilter()
476-
transform.SetInputData(append.GetOutput())
477-
transform.SetTransform(transFunc)
478-
transform.Update()
528+
def GetMeridian(self):
529+
'''
530+
Returns the central meridian
531+
'''
532+
return self._center_meridian
479533

480-
outData.ShallowCopy(transform.GetOutput())
534+
def RequestData(self, request, inInfo, outInfo):
535+
inData = self.GetInputData(inInfo, 0, 0)
536+
inPoints = inData.GetPoints()
537+
inCellArray = inData.GetCells()
538+
539+
outData = self.GetOutputData(outInfo, 0)
540+
if self._cached_output and self._cached_output.GetMTime() > inPoints.GetMTime() and \
541+
self._cached_output.GetMTime() > inCellArray.GetMTime():
542+
# only scalars have been added or removed
543+
cached_cell_data = self._cached_output.GetCellData()
544+
545+
in_cell_data = inData.GetCellData()
546+
547+
outData.ShallowCopy(self._cached_output)
548+
out_cell_data = outData.GetCellData()
549+
550+
out_cell_data.Initialize()
551+
for i in range(in_cell_data.GetNumberOfArrays()):
552+
in_array = in_cell_data.GetArray(i)
553+
cached_array = cached_cell_data.GetArray(in_array.GetName())
554+
if cached_array and cached_array.GetMTime() >= in_array.GetMTime():
555+
# this scalar has been seen before
556+
# simply add a reference in the outData
557+
out_cell_data.AddArray(in_array)
558+
else:
559+
# this scalar is new
560+
# we have to fill in the additional cells resulted from the clip
561+
out_array = in_array.NewInstance()
562+
array0 = cached_cell_data.GetArray(0)
563+
out_array.SetNumberOfComponents(array0.GetNumberOfComponents())
564+
out_array.SetNumberOfTuples(array0.GetNumberOfTuples())
565+
out_array.SetName(in_array.GetName())
566+
out_cell_data.AddArray(out_array)
567+
outData.cell_data[out_array.GetName()] = inData.cell_data[i][self._cached_output.cell_data['PedigreeIds']]
568+
else:
569+
generate_ids = vtkGenerateIds()
570+
generate_ids.SetInputData(inData)
571+
generate_ids.PointIdsOff()
572+
generate_ids.SetCellIdsArrayName("PedigreeIds")
573+
574+
cut_meridian = self._center_meridian + 180
575+
plane = vtkPlane()
576+
plane.SetOrigin([cut_meridian, 0.0, 0.0])
577+
plane.SetNormal([-1, 0, 0])
578+
# vtkClipPolyData hangs
579+
clipL = vtkTableBasedClipDataSet()
580+
clipL.SetClipFunction(plane)
581+
clipL.SetInputConnection(generate_ids.GetOutputPort())
582+
clipL.Update()
583+
584+
plane.SetNormal([1, 0, 0])
585+
clipR = vtkTableBasedClipDataSet()
586+
clipR.SetClipFunction(plane)
587+
clipR.SetInputConnection(generate_ids.GetOutputPort())
588+
clipR.Update()
589+
590+
transFunc = vtkTransform()
591+
transFunc.Translate(-360, 0, 0)
592+
transform = vtkTransformFilter()
593+
transform.SetInputData(clipR.GetOutput())
594+
transform.SetTransform(transFunc)
595+
transform.Update()
596+
597+
append = vtkAppendFilter()
598+
append.AddInputData(clipL.GetOutput())
599+
append.AddInputData(transform.GetOutput())
600+
append.Update()
601+
outData.ShallowCopy(append.GetOutput())
602+
self._cached_output = outData.NewInstance()
603+
self._cached_output.ShallowCopy(outData)
481604
return 1

src/e3sm_quickview/plugins/eam_reader.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@ def _markmodified(*args, **kwars):
221221
</StringVectorProperty>
222222
"""
223223
)
224+
@smproperty.xml(
225+
"""
226+
<IntVectorProperty command="SetForceFloatPoints"
227+
name="ForceFloatPoints"
228+
default_values="1"
229+
number_of_elements="1">
230+
<BooleanDomain name="bool" />
231+
<Documentation>
232+
If True, the points of the dataset will be float, otherwise they will be float or double depending
233+
on the type of corner_lat and corner_lon variables in the connectivity file.
234+
</Documentation>
235+
</IntVectorProperty>
236+
"""
237+
)
224238
class EAMSliceSource(VTKPythonAlgorithmBase):
225239
def __init__(self):
226240
VTKPythonAlgorithmBase.__init__(
@@ -230,6 +244,7 @@ def __init__(self):
230244

231245
self._DataFileName = None
232246
self._ConnFileName = None
247+
self._ForceFloatPoints = True
233248
self._dirty = False
234249

235250
# Variables for dimension sliders
@@ -448,7 +463,12 @@ def _build_geometry(self, meshdata):
448463
lat = meshdata[latdim][:].data.flatten()
449464
lon = meshdata[londim][:].data.flatten()
450465

451-
coords = np.empty((len(lat), 3), dtype=np.float64)
466+
467+
if self._ForceFloatPoints:
468+
points_type = np.float32
469+
else:
470+
points_type = np.float64 if lat.dtype == np.float64 else np.float32
471+
coords = np.empty((len(lat), 3), dtype=points_type)
452472
coords[:, 0] = lon
453473
coords[:, 1] = lat
454474
coords[:, 2] = 0.0
@@ -579,6 +599,11 @@ def SetConnFileName(self, fname):
579599
self._populate_variable_metadata()
580600
self.Modified()
581601

602+
def SetForceFloatPoints(self, forceFloatPoints):
603+
if self._ForceFloatPoints != forceFloatPoints:
604+
self._ForceFloatPoints = forceFloatPoints
605+
self.Modified()
606+
582607
def SetSlicing(self, slice_str):
583608
# Parse JSON string containing dimension slices and update self._slices
584609

0 commit comments

Comments
 (0)