Field Transfer Threads Performace¶
Import¶
[1]:
from Muscat.Containers.MeshFieldOperations import GetFieldTransferOpCpp, GetFieldTransferOpPython
from Muscat.Containers.MeshCreationTools import CreateCube
from Muscat.FE.FETools import PrepareFEComputation
from Muscat.FE.Fields.FEField import FEField
from Muscat.Containers.ConstantRectilinearMeshTools import CreateConstantRectilinearMesh
from Muscat.LinAlg.Transform import Transform
from Muscat.Helpers.TextFormatHelper import TFormat
from Muscat.Containers.NativeTransfer import NativeTransfer
import numpy as np
import time
import pyvista
pyvista.global_theme._jupyter_backend = 'panel' # remove this line to get interactive 3D plots
Mesh and Target Points Generation¶
[2]:
N = 50
inputmesh = CreateCube(dimensions=[N, N, N], origin=[-1.0] * 3, spacing=[2 / (N - 1), 2 / (N - 1), 2 / (N - 1)])
inputFEField = FEField(name="3DTo3DNative", mesh=inputmesh)
N = 60
outmesh = CreateConstantRectilinearMesh(dimensions=[N, N, N], origin=[-1.0] * 3, spacing=[2 / (N - 1), 2 / (N - 1), 2 / (N - 1)])
print("Input mesh:")
print(inputmesh)
print("Output mesh:")
print(outmesh)
Input mesh:
Mesh
Number Of Nodes : 125000
Tags : (x0y0z0:1) (x1y0z0:1) (x0y1z0:1) (x1y1z0:1) (x0y0z1:1) (x1y0z1:1) (x0y1z1:1) (x1y1z1:1)
Number Of Elements : 132055
StructuredElementContainer([50 50 50]), Type : (ElementType.Hexahedron_8,117649), Tags : (3D:117649)
ElementsContainer, Type : (ElementType.Quadrangle_4,14406), Tags : (Skin:14406) (X0:2401) (X1:2401) (Y0:2401) (Y1:2401) (Z0:2401) (Z1:2401)
Output mesh:
Mesh
Number Of Nodes : 216000
Tags :
Number Of Elements : 205379
StructuredElementContainer([60 60 60]), Type : (ElementType.Hexahedron_8,205379), Tags :
Deform output mesh¶
Make the problem more realistic
[3]:
op = Transform()
op.keepNormalized = False
op.keepOrthogonal = False
op.SetFirst([1.4, 0.56, 0])
op.SetSecond([-1.135, 1.42486, 1.6102])
outmesh.nodes = np.ascontiguousarray(op.ApplyTransform(outmesh.nodes))
Generate Data¶
[4]:
x = inputmesh.nodes[:, 0]
y = inputmesh.nodes[:, 1]
data = (x - 0.5) ** 2 - y * 0.5 + x * y * 0.25
Start transfer timing…¶
[5]:
print(f"Number of elements in the origin mesh = {inputmesh.GetNumberOfElements()}")
print(f"Number of points in the target cloud point = {outmesh.GetNumberOfNodes()}")
Number of elements in the origin mesh = 132055
Number of points in the target cloud point = 216000
Some utilities¶
[6]:
def PrintRow(datarow):
res = "|"
for d in datarow:
if type(d) is str:
res += TFormat.Center(str(d), fill=" ", width=20) + "|"
else:
res += TFormat.Center("%.4f" % d, fill=" ", width=20) + "|"
print(res)
Initialization¶
[7]:
setFieldTime = time.time()
nt = NativeTransfer()
nt.SetVerbose(False)
searchStrategies = ((True,False,False,False),
(False,True,False,False),
(False,True,True,False),
(False,False,False,True),
(True,True,False,True))
for ss in searchStrategies:
nt.SetUsePointSearch(ss[0])
nt.SetUseElementSearch(ss[1])
nt.SetUseElementSearchFast(ss[2])
nt.SetUseEdgeSearch(ss[3])
setFieldTime = time.time()
nt.SetSourceFEField(inputFEField)
st = time.time() - setFieldTime
print(f"Set Up time (SetSourceFEField) for {ss} : {st} [s]")
Set Up time (SetSourceFEField) for (True, False, False, False) : 0.11120080947875977 [s]
Set Up time (SetSourceFEField) for (False, True, False, False) : 0.09433293342590332 [s]
Set Up time (SetSourceFEField) for (False, True, True, False) : 0.09303522109985352 [s]
Set Up time (SetSourceFEField) for (False, False, False, True) : 0.2518117427825928 [s]
Set Up time (SetSourceFEField) for (True, True, False, True) : 0.25812458992004395 [s]
Threads Scalability¶
[8]:
nt.SetUsePointSearch(True)
nt.SetUseElementSearch(False)
nt.SetUseElementSearchFast(False)
nt.SetUseEdgeSearch(False)
nt.SetSourceFEField(inputFEField)
[9]:
from Muscat.Helpers.CPU import GetNumberOfAvailableCores
print(f"GetNumberOfAvailableCores: {GetNumberOfAvailableCores()}")
nbCores = (np.arange(int(np.ceil(np.sqrt(GetNumberOfAvailableCores()))))**2+1)
nbCores[-1] = GetNumberOfAvailableCores()
GetNumberOfAvailableCores: 1
[10]:
print(f"Set Up time (SetSourceFEField) {st} [s]")
print("_"*(8*20+9))
output = ["method"]
output.extend(f"cpp [s] {th} thread " for th in nbCores)
output.extend(f"speedup {th}/1 " for th in nbCores[1:])
PrintRow(output)
for method in ["Interp/Nearest", "Nearest/Nearest", "Interp/Clamp", "Interp/Extrap"]:
nt.SetTransferMethod(method)
nt.SetTargetPoints(outmesh.nodes)
times = []
for nbThreads in nbCores:
nt.SetMaxConcurrency(nbThreads)
cppStartTime = time.time()
nt.Compute()
cppStopTime = time.time()
op = nt.GetOperator()
times.append(cppStopTime - cppStartTime)
output = [method]
output.extend(times)
output.extend([times[0] / (t if t > 0 else 1) for t in times[1:]])
PrintRow(output)
Set Up time (SetSourceFEField) 0.25812458992004395 [s]
_________________________________________________________________________________________________________________________________________________________________________
| method | cpp [s] 1 thread |
| Interp/Nearest | 2.9964 |
| Nearest/Nearest | 0.4111 |
| Interp/Clamp | 3.0013 |
| Interp/Extrap | 3.0070 |