meshpro / dmsh Goto Github PK
View Code? Open in Web Editor NEW:spider_web: Simple mesh generator inspired by distmesh.
License: GNU General Public License v3.0
:spider_web: Simple mesh generator inspired by distmesh.
License: GNU General Public License v3.0
I have a new machine with Windows 11 and have installed Anaconda3-2021.11-Windows-x86_64.
Tried running in powershell window:
conda install dmsh
Not found.
Tried:
pip install dmsh
This installed dmsh.
But get following error when running a simple dmsh application that ran on my old Windows 10 machine:
ImportError: cannot import name 'NDArray' from 'numpy.typing' (C:\Users\Graham\anaconda3\lib\site-packages\numpy\typing\__init__.py)
The installed numpy version = 1.20.3
Debian CI tests for dmsh are failing norm_equality assertions, see https://ci.debian.net/packages/p/python-dmsh/unstable/amd64/
e.g.
running test_ellipse.py
Traceback (most recent call last):
File "test_ellipse.py", line 17, in <module>
X, cells = test_ellipse(show=False)
File "test_ellipse.py", line 12, in test_ellipse
assert_norm_equality(X.flatten(), ref_norms, 1.0e-12)
File "/tmp/autopkgtest-lxc.gfrwhpig/downtmp/build.UWT/src/test/helpers.py", line 16, in assert_norm_equality
*ref_norm, *vals
AssertionError: Expected: [2.5108886251367960e+02, 1.5652935519539316e+01, 1.9890059982474428e+00]
Computed: [2.5384746773734730e+02, 1.5749252942957204e+01, 1.9968359662268518e+00]
It looks like it's not as simple as just relaxing the tolerance from 1e-12. The amount of deviation is larger than 1%, too large to be just an issue of machine precision.
Unfortunately I can't reproduce the error on my own computer, where the tests pass fine, so difficult to debug.
I created a new anaconda environment on Python 3.9 and installed dmsh using pip. I'm trying to run the examples now, but I get an error at the first line basically.
import dmsh
import meshio
import optimesh
geo = dmsh.Circle([0.0, 0.0], 1.0)
X, cells = dmsh.generate(geo, 0.1)
AttributeError: 'MeshTri' object has no attribute 'node_coords'
Would like to get feedback on approaches to make dmsh the following:
This tool would be very useful in finding the most even way to pack out a set of polygons with n number of points.
Hi @nschloe
I enjoy your work. I have been searching for solutions to create mesh'es using Python and then I came across dmsh.
Even though it is working, I could, however, use some further documentation in regards to some parameters. That is, instead of looking at the Python files itself.
Let's look at the very first segment of code. Here, there is a line:
X, cells = dmsh.generate(geo, 0.1)
It is the parameter of 0.1
that I have my doubts about, which is the target_edge_size
, right? I really could use some explanation/documentation about this. I mean, what is the "size" telling us? Is it the length of an edge? Is it the area of a triangle? What exactly?
Same goes for your other repositories, meshio
and optimesh
, where parameters for the latter ones are confusing. I will just write it here instead of another issue on those repos.
This line for instance:
X, cells = optimesh.optimize_points_cells(X, cells, "CVT (full)", 1.0e-10, 100)
"CVT (full)"
is the method I suppose? Is there a list in your repository for other methods? I am looking for the correct syntax.1.0e-10
is the tolerance, yeah? Tolerance of what?100
- this number makes me insecure? Is this the iterations when the mesh is being optimized?IMO, the explanation doesn't have to be long - but just think about it, when you are developing your hard work :)
setup.cfg contains configuration for console apps
[options.entry_points]
console_scripts =
dmsh-image = dmsh.cli:image
dmsh-poly = dmsh.cli:poly
This causes /usr/bin/dmsh-image and /usr/bin/dmsh-poly to be created. But running the apps fails, since there is no dmsh.cli
,
dmsh-image
Traceback (most recent call last):
File "/usr/bin/dmsh-image", line 33, in <module>
sys.exit(load_entry_point('dmsh==0.2.3', 'console_scripts', 'dmsh-image')())
File "/usr/bin/dmsh-image", line 25, in importlib_load_entry_point
return next(matches).load()
File "/usr/lib/python3.8/importlib/metadata.py", line 77, in load
module = import_module(match.group('module'))
File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 973, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'dmsh.cli'
Should these console_scripts
entries be removed?
Since there is no dmsh.cli, I guess the entries should be removed.
I'm trying to create several holes in a Polygon but the Difference method only accepts 2 geometries: The external one and 1 inside.
I would like to know if it's possible to use the method Difference of DMSH for more than 1 geometry. This is one example:
is it possible to do that with DMSH?
Thank you in advance!
What is the best way to extract boundary node indices from a finished mesh?
Show the error
ImportError: cannot import name 'NDArray' from 'numpy.typing'
Dear Authors,
Thank you for your excellent job.
I found the geometrical parameters (e.g. radius, length of rectangle) are all less then 5 in your examples. When I tried some others like lenght>10, the program went dead and crashed with nothing appearing on the command line window.
My codes are listed as followed:
r = dmsh.Rectangle(-10.0, +20.0, -10.0, +20.0)
c = dmsh.Circle([.0, .0], 3)
geo = dmsh.Difference(r, c)
np.random.seed(0)
X, cells = dmsh.generate(
geo, 0.25, tol=1.0e-10
)
plt.triplot(X[:,0], X[:,1], cells)
plt.show()
Could you give some advice?
Thank you!
Let's take this geo (but it happens for every other shape I tried as well):
These are the boundary coords:
boundary_e=[[124.0, 18.0], [75.0, 33.0], [51.0, 54.0], [31.0, 86.0], [19.0, 124.0], [14.0, 183.0], [18.0, 221.0], [33.0, 269.0], [64.0, 310.0], [93.0, 326.0], [122.0, 332.0], [185.0, 327.0], [220.0, 311.0], [254.0, 285.0], [254.0, 156.0], [145.0, 156.0], [145.0, 215.0], [193.0, 215.0], [194.0, 248.0], [155.0, 269.0], [130.0, 269.0], [111.0, 260.0], [92.0, 234.0], [84.0, 190.0], [84.0, 159.0], [94.0, 112.0], [110.0, 91.0], [131.0, 81.0], [159.0, 84.0], [184.0, 116.0], [250.0, 101.0], [242.0, 72.0], [216.0, 36.0], [197.0, 25.0], [162.0, 18.0], [125.0, 19.0]]
dmsh.Polygon(boundary_e)
Then "dmsh.generate(geo, edge_size=20, verbose = False)" leads to:
.../python3.6/site-packages/meshplex/base.py", line 17, in compute_tri_areas
assert numpy.all(vol2 > -1.0e-14)
AssertionError
Fatal Python error: Aborted
This didn't happen when I had a previos version of meshplex. Maybe the last update caused it.
Is it possible to use a distance function to implicitly define a geometry and mesh it (as in PyDishMesh)?
E.g. (from PyDistMesh),
circle = lambda p: np.sqrt((p**2).sum(1))-1.0
points, cells = dmsh.generate(circle, 0.1)
Thanks
Some problems occur on the boundary: How to make a non-boundary cell a boundary cell and the other way around etc.
Hello,
For certain custom geometries, I get AssertionError: Exceeded maximum number of boundary steps.
when meshing. Is there any way around this, or to specify the amount of boundary steps I would like?
Hello,
On one side, I'm would like to know if it's possible with DMSH to force mesh to pass through specific point. For instance, I would like to have a mesh node in the center of each small green circle (each circle should be modeled as a mesh node)
On the other side, I would like to know if is possible to make coincide the nodes of different regions along each side. For example:
Thank you in advance!
After meshplex 0.15.4, several dmsh tests are now failing: test_halfspace, test_large, test_pacman, test_rectangle, test_rectangle_hole, etc. e.g.
________________________________ test_halfspace ________________________________
show = False
def test_halfspace(show=False):
geo = dmsh.Intersection(
[
dmsh.HalfSpace(numpy.sqrt(0.5) * numpy.array([1.0, 1.0]), 0.0),
dmsh.Circle([0.0, 0.0], 1.0),
]
)
X, cells = dmsh.generate(geo, 0.1, show=show)
ref_norms = [1.6445956676826719e02, 1.0032819728269299e01, 9.9962353342404042e-01]
> assert_norm_equality(X.flatten(), ref_norms, 1.0e-6)
test/test_halfspace.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
X = array([-0.70710678, 0.70710678, 0.70710678, -0.70710678, 0.6450446 ,
-0.6450446 , 0.58124506, -0.58124506, ... -0.07271509,
0.99735275, 0.03101633, 0.99951888, 0.13299572, 0.99111661,
0.23490238, 0.97201897])
ref_norm = array([164.45956677, 10.03281973, 0.99962353]), tol = 1e-06
def assert_norm_equality(X, ref_norm, tol):
ref_norm = numpy.asarray(ref_norm)
vals = numpy.array(
[
numpy.linalg.norm(X, ord=1),
numpy.linalg.norm(X, ord=2),
numpy.linalg.norm(X, ord=numpy.inf),
]
)
> assert numpy.all(
numpy.abs(vals - ref_norm) < tol * ref_norm
), "Expected: [{:.16e}, {:.16e}, {:.16e}]\nComputed: [{:.16e}, {:.16e}, {:.16e}]".format(
*ref_norm, *vals
)
E AssertionError: Expected: [1.6445956676826719e+02, 1.0032819728269299e+01, 9.9962353342404042e-01]
E Computed: [1.6391103448060974e+02, 1.0020943433490697e+01, 9.9999732753403403e-01]
test/helpers.py:21: AssertionError
Looks like the dmsh expected values need to be updated in the wake of meshplex 0.15.4.
Several of the dmsh 0.1.5 tests display a plot of the mesh when show=True
is provided to dmsh.generate. Some of them cycle repeatedly display the mesh many many times. The worst offender is test_union_rectangles.py
, but test_square_hole.py
also displays many times before stopping*.
I presume there is some iteration taking place for the generation of these test meshes, and some matplotlib code is set to show the plot at each iteration.
pytest-3
rather than python3 test_circle.py
Might be useful for domains with large differences in cell sizes, see #86 (comment).
Hi there
Right now there are an issue when taking a .Difference of a .Difference.
I am using your generator for my project (my bachelors thesis actually) and I need geoms with multiple holes.
I will try to fix that, but I first gotta go through your code.
PS: Your repos on meshing are very good and helpful. Thanks a lot!
Hello,
Thank you for your work, could you please implement the 3d-surface mesh like sphere? I tried by myself, but I am not familiar with matlab. Thank you.
Working with Python 3.9.13, on Windows, from within Jupyter, I ran:
!pip3 install dmsh
. . .
. . .
Collecting dmsh
Using cached dmsh-0.2.21-py3-none-any.whl (164 kB)
Using cached dmsh-0.2.20-py3-none-any.whl (164 kB)
The conflict is caused by:
dmsh 0.2.23 depends on meshplex<0.19.0 and >=0.16.0
dmsh 0.2.22 depends on meshplex<0.19.0 and >=0.16.0
dmsh 0.2.21 depends on meshplex<0.19.0 and >=0.16.0
dmsh 0.2.20 depends on meshplex<0.19.0 and >=0.16.0
To fix this you could try to:
And then I ran
!pip3 index versions meshplex
meshplex (0.19.1)
Available versions: 0.19.1
I don't know how to handle this. Can you advise?
thanks
Gary Bollenbach
I have found that dmsh
sometimes generates duplicate points, which makes it difficult to use with meshless methods as this can result in singular matrices. An example is given below which produces three duplicate points.
import dmsh
import optimesh
geo = dmsh.Union([dmsh.Rectangle(-1.0, +1.0,-0.2, +0.2),
dmsh.Rectangle(+0.5, +1.0,-0.6, +1.0),
dmsh.Circle([-0.5, 0.0], 0.4)])
geo = dmsh.Difference(geo, dmsh.Circle([+0.5, 0.2], 0.2))
r = 0.1
pts, cells = dmsh.generate(geo, edge_size=r, tol=1.0e-10)
# optionally optimize the mesh
pts, cells = optimesh.optimize_points_cells(pts, cells, "CVT (full)",
1.0e-10, 100)
dmsh.helpers.show(pts, cells, geo)
I note there is a helper function unique_rows()
that may help, but is there a function call that can delete duplicate points and also the associated cells?
I've recently started using dmsh to generate some simple grids, and after some testing I've noticed that some cells are missing close or at the boundary, even using primitive classes. Is this an expected behavior?
Python script:
import dmsh
import optimesh
import numpy as np
c1 = dmsh.Circle([0.0,0.0],1.0)
X, cells = dmsh.generate(c1,0.1,tol=1.0e-10)
X, cells = optimesh.cvt.quasi_newton_uniform_full(X, cells, 1.0e-10,200)
np.savetxt("nodeCoords.txt", X, delimiter=" ")
np.savetxt("cellIndices.txt", cells, fmt='%i', delimiter=" ")
with open("toplot.txt","w") as toplotFile:
for cell in range(len(cells)):
for i in range(3):
node = cells[cell][i]
nodeX = X[node][0]
nodeY = X[node][1]
toplotFile.write(str(nodeX)+" "+str(nodeY)+"\n")
toplotFile.write("\n")
gnuplot script:
set size ratio -1
p "toplot.txt" w l
Thank you very much.
How could I accomplish Difference(Geo0, Geo1, Geo2)? Directly, I tried Difference(Geo0, Geo1, Geo2), and it does not work for this manipulation. Actually, I tried GeoTemp = Difference(Geo0, Geo1), Geo = Difference(GeoTemp, Geo2), it still failed.
I check out the code of Difference, multi-operation seems not to be supported. Does this function only support the Difference for two geometries? Is there any other option for several times of Difference?
Thank you!
Seems to be a new bug in test_union_three_circles.py in 0.1.5:
running test_union_three_circles.py
Traceback (most recent call last):
File "test_union_three_circles.py", line 24, in <module>
X, cells = test_union(show=False)
File "test_union_three_circles.py", line 16, in test_union
X, cells = dmsh.generate(geo, 0.2, show=show, tol=1.0e-10)
File "/usr/lib/python3/dist-packages/dmsh/main.py", line 163, in generate
pts[is_outside] = geo.boundary_step(pts[is_outside].T).T
File "/usr/lib/python3/dist-packages/dmsh/geometry/union.py", line 63, in boundary_step
out[:, j] = geo.boundary_step(out[:, j])
IndexError: boolean index did not match indexed array along dimension 1; dimension is 48 but corresponding boolean dimension is 46
cf. https://ci.debian.net/data/autopkgtest/unstable/amd64/p/python-dmsh/3670232/log.gz
https://ci.debian.net/packages/p/python-dmsh/unstable/amd64/
Hi,
In my rectangular mesh I wanted to fix some nodes, two per side at 1/3rd of them, but with the optimisation process nodes are placed by the algorithm at various positions.
Is it possible to declare a vector of fixed nodes which is then completed by the algorithm to construct the mesh ? In particular on a circle, if I want to fix 8 nodes on the border at equal distance from each other it should still be possible.
Thank you in advance for your help !
NB : I can, once the nodes are generated, select the ones "near" the positions I wanted but it's not sufficient.
I'm trying to mesh 2 surfaces in different planes. However, I need to have common nodes in the common vertex. To do that, I tried 2 thigs:
However, in both cases I'm able to have common nodes in both surfaces but new nodes appear in the middle suddenly. How can I avoid this?
Thank you in advance.
I want to implement a simple poisson problem
For example, I have a boundary of an arbitrary shape on an image. It could not be parameterized by your function
Hey again,
Since distmesh has no "good" convergence criteria (although differencing some median mesh quality measurement has worked for me in the past), wouldn't it make more sense to let the program complete a set of fixed iterations and then return the connectivity and points instead of asserting and haulting the program?
Generally, 50 to 100 works then I typically do some standard mesh improvement stuff.
just a suggestion,
`import dmsh
geo = dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0)
X, cells = dmsh.generate(geo, 0.1)`
AttributeError Traceback (most recent call last)
in
2
3 geo = dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0)
----> 4 X, cells = dmsh.generate(geo, 0.1)
~/.miniconda/envs/dvlpy/lib/python3.7/site-packages/dmsh/main.py in generate(geo, edge_size, tol, random_seed, show, max_steps, verbose, flip_tol)
211 delta_t=0.2,
212 f_scale=1 + 0.4 / 2 ** (dim - 1), # from the original article
--> 213 flip_tol=flip_tol,
214 )
215 points = mesh.points
~/.miniconda/envs/dvlpy/lib/python3.7/site-packages/dmsh/main.py in distmesh_smoothing(mesh, geo, num_feature_points, edge_size_function, max_steps, tol, verbose, show, delta_t, f_scale, flip_tol)
233 ):
234 print(type(mesh))
--> 235 mesh.create_edges()
236
237 k = 0
AttributeError: 'MeshTri' object has no attribute 'create_edges'
I have just upgraded to dmsh-0.2.10
and optimesh-0.8.0
and tried to run the following test example,
# Ref: https://pypi.org/project/dmsh/
import dmsh
geo = dmsh.Circle([0.0, 0.0], 1.0)
X, cells = dmsh.generate(geo, 0.1)
# optionally optimize the mesh
import optimesh
X, cells = optimesh.cvt.quasi_newton_uniform_full(X, cells, 1.0e-10, 100)
# visualize the mesh
dmsh.helpers.show(X, cells, geo)
but it throws the following error:
File "C:\MathsProjects\python\dmsh\circle.py", line 11, in <module>
X, cells = optimesh.cvt.quasi_newton_uniform_full(X, cells, 1.0e-10, 100)
AttributeError: module 'optimesh.cvt' has no attribute 'quasi_newton_uniform_full'
Any advice on how the optimesh
statement should be changed?
By the way I also have meshplex-0.15.5
installed.
It may be expected but I was hoping that the output would return the same points along the polygon without extra points.
It appears that additional boundary points are added to the edges of a polygon. given a polygon with 58 points and a custom edge length, the output adds additional points on the edge of the mesh. converting the mesh to vtk and extracting the edge with FeatureEdges, the point count on the outer edge is 97 in the case below.
Example:
import vtk
import numpy as np
import meshio
import dmsh
poly = [[1.1207656860351562, -1.474766731262207], [0.9311693906784058, -1.6106348037719727],
[0.7221899032592773, -1.7151135206222534], [0.5003705620765686, -1.7881356477737427],
[0.24269625544548035, -1.8346717357635498], [0.039923492819070816, -1.8448166847229004],
[-0.1640581488609314, -1.8532711267471313], [-0.3358287513256073, -1.8202623128890991],
[-0.5591791868209839, -1.757102131843567], [-0.724500298500061, -1.7027467489242554],
[-0.8599539995193481, -1.64866304397583], [-1.0511908531188965, -1.5159660577774048],
[-1.2156579494476318, -1.3969435691833496], [-1.3622872829437256, -1.2560036182403564],
[-1.505843997001648, -1.0733786821365356], [-1.6370562314987183, -0.8811505436897278],
[-1.702138900756836, -0.718871533870697], [-1.7739341259002686, -0.5288633108139038],
[-1.8255635499954224, -0.3319735527038574], [-1.8417296409606934, -0.10016066581010818],
[-1.848059058189392, 0.1026785671710968], [-1.8210378885269165, 0.30386221408843994],
[-1.783565640449524, 0.5339696407318115], [-1.7262778282165527, 0.6997944712638855],
[-1.645498275756836, 0.8552301526069641], [-1.5460537672042847, 1.0332894325256348],
[-1.4829825162887573, 1.0954675674438477], [-1.3618178367614746, 1.258979320526123],
[-1.2313412427902222, 1.3749150037765503], [-1.1004729270935059, 1.4900223016738892],
[-0.9327254295349121, 1.605852484703064], [-0.7736870050430298, 1.6783183813095093],
[-0.5828970074653625, 1.7475013732910156], [-0.4182337522506714, 1.8048688173294067],
[-0.1892661303281784, 1.8489644527435303], [0.014770971611142159, 1.8476674556732178],
[0.2173810601234436, 1.833501935005188], [0.41810983419418335, 1.8017268180847168],
[0.5875660181045532, 1.7592521905899048], [0.7782935500144958, 1.6866511106491089],
[0.9074407815933228, 1.6185364723205566], [1.0574780702590942, 1.5281968116760254],
[1.2203333377838135, 1.4045077562332153], [1.354766607284546, 1.2504076957702637],
[1.4904139041900635, 1.098829746246338], [1.6049500703811646, 0.9301034808158875],
[1.711469292640686, 0.722557544708252], [1.7588528394699097, 0.5539127588272095],
[1.811102271080017, 0.38747504353523254], [1.8434756994247437, 0.18628628551959991],
[1.8454340696334839, -0.01729956641793251], [1.843611478805542, -0.19182713329792023],
[1.8114262819290161, -0.3634224832057953], [1.7626954317092896, -0.5608553290367126],
[1.684820294380188, -0.7485829591751099], [1.6166356801986694, -0.9093696475028992],
[1.5086168050765991, -1.0823739767074585], [1.39910089969635, -1.2188986539840698]]
def inverse_circle_generator(R, N_edges):
# need to check that the shape of the equation is correct
# also need to add a check that the R is passed
R_ = R
c = 2.0*np.pi / N_edges
N_mult = 2.8
k1 = N_mult * c
k2 = (N_mult-1.0) / N_mult
def inverse_circle(p):
r = np.sqrt(np.sum(np.square(p), axis=0))
r[r > R_] = R_
r[r < 0.0] = 0.0
h = k1 * R_*(1.0 - k2 / R_ * r)
return h
return inverse_circle
geo = dmsh.Polygon(poly)
edge_length = inverse_circle_generator(1.850, len(poly)*1.5)
x, cells = dmsh.generate(geo, edge_length, delta_t=0.1, tol=1.0e-6)
mesh = meshio.Mesh(x, {"triangle":cells})
meshio.write("test.vtu", mesh)
print(len(poly), x.shape)
pts = vtk.vtkPoints()
polygon = vtk.vtkPolygon()
cells = vtk.vtkCellArray()
pd = vtk.vtkPolyData()
for idx, pt in enumerate(poly):
pts.InsertNextPoint(pt[0], pt[1], 0.0)
polygon.GetPointIds().InsertNextId(idx)
cells.InsertNextCell(polygon)
pd.SetPoints(pts)
pd.SetPolys(cells)
writer = vtk.vtkXMLPolyDataWriter()
writer.SetFileName("polygon.vtp")
writer.SetInputConnection(pd.GetOutputPort())
writer.SetInputData(pd)
writer.Write()
The red dots are the polygon points and the green dots are the edge points from dmsh.
It looks like it keeps the polygon points but adds additional points. is there a way to constrain it to not add additional points on the boundary? does gmsh provide this kind of constraint?
Thank you so much for your time.
Is it possible to insert the number of points (X) as a parameter instead of the edge_size, then perform meshing, so that the number of vertices obtained at the end is the one we chose before.
Do you have any recommendation??
I did not try to do that because in this case I should modify the source code.
I tried some methods like choosing the edge_size corresponding the the wanted number of cells but i does not give a good estimate of edge_size.
Any recommendation or help?? thanks
Is there a way of ordering the set of boundary points of boundary edges, clockwise/anticlockwise?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.