boutproject / hypnotoad Goto Github PK
View Code? Open in Web Editor NEWPython grid generator for BOUT++ https://hypnotoad.readthedocs.io/en/latest/
License: GNU General Public License v3.0
Python grid generator for BOUT++ https://hypnotoad.readthedocs.io/en/latest/
License: GNU General Public License v3.0
The way parallelism is implemented requires pickling (using dill
) to transfer information between processes. Some change between versions 0.3.4 and 0.3.5 of dill broke things in a couple of ways. Options
objects from optionsfactory
stopped being picklable - this is now fixed in the latest version (see johnomotani/optionsfactory#16), but pickling of TokamakEquilibrium
objects is still failing - see uqfoundation/dill#510.
List of things that should be added to the manual:
PsiContour
/FineContour
, used especially for nonorthogonal gridsThe GUI gives an error message:
"'-o' is not a valid value for ls; supported values are '-', '--', '-.', ':', 'None', ' ', '', 'solid', 'dashed', 'dashdot', 'dotted'"
/common/projects/physics/SOLTransport/repos_eric/hyp_env/hypnotoad/hypnotoad/core/equilibrium.py:649: UserWarning: FineContour: maximum iterations (200) exceeded with ds_error 4.5852703535118056e-10
warnings.warn(
The example in examples/tokamak/tokamak_example.py
seems to be broken, I get an error
$ ./tokamak_example.py lower-double-null.yaml
Traceback (most recent call last):
File "./tokamak_example.py", line 99, in <module>
r1d, z1d, psi2d, [], [], options=options # psi1d, fpol
TypeError: __init__() got an unexpected keyword argument 'options'
The MeshRegion
class includes methods that calculate geometric quantities for the standard BOUT++ locally field aligned coordinate system. Ideally MeshRegion
would be generic, with the BOUT++ specific parts separated out into a derived class, e.g. BoutMeshRegion
(which would then be created by BoutMesh
). At the moment the only use of hypnotoad
is for BOUT++, so this is not a priority at the moment.
It would be really nice to create an "expected output" grid file and use it for regression testing. Maybe 3 tests - single null, connected double null and disconnected double null?
It would be nice if the GUI showed the direction of the poloidal (add arrow-heads to the psi contours?) and toroidal (maybe a text box with 'B_t is clockwise from above' or 'B_t is anticlockwise from above?) magnetic fields, to make them easy to check.
Even when using non-orthogonal grids, the MeshRegion
boundaries at X-point locations are defined by lines perpendicular to flux surfaces. This can cause problems for short-leg divertors, e.g. the region boundary could even intersect the wall (thanks @mikekryjak for finding this case!).
In principle it should be straightforward to add an option to choose the region boundary in a different way here
hypnotoad/hypnotoad/core/mesh.py
Lines 213 to 267 in 82a0121
gradPsiSurfaceAtStart
and gradPsiSurfaceAtEnd
member variables to something more generic).
For example, the boundary could just be a straight line going away from the X-point at some specified angle (with some check that it is actually pointing into the right region and does not intersect the separatrix).
One fiddly part would be naming the options and looking up the right one for each MeshRegion
, depending which divertor leg (and which radial side) the boundary belongs to.
I tried to generate some non-orthogonal grids as a test, and got quite a few failures with an exception raised due to PsiContour.distance
not being monotonic. Not sure if this was just due to the equilibrium I was using or low resolution, but it should not be happening. Distance is calculated on PsiContours by interpolating from FineContours. The way the interpolation is done means (if I remember correctly) that the distance on a PsiContour point is always in between the distance on the nearest two FineContour points, so it's always greater than the smaller of those two distances. Then if the FineContour does not reach all the way to the end of the PsiContour, the end point or two of the PsiContour can get incorrect distances, roughly as if their 'distance' is the absolute value of the distance from wherever the end of the FineContour is, so that on the first few points the 'distance' decreases (until it reaches the start of the FineContour) and then increases again. So my best guess is that the error is something to do with this, although the FineContours are supposed to extend past the end of the PsiContours so that this does not happen. There is a check/fix to make sure FineContours extend far enough here
hypnotoad/hypnotoad/core/mesh.py
Line 728 in 94c6af3
I don't have time to make a minimal, reproducible example now, or to debug further, so leaving a note in case the same errors crop up in future...
Ideally the calculation of the curvature, Curl(b/B), should not use finite-difference derivatives on the grid, but rather derivatives of the interpolated psi-function. An implementation of this was started but not completed in MeshRegion.calc_curvature()
here
hypnotoad/hypnotoad/core/mesh.py
Lines 1318 to 1455 in c442734
At least when creating a grid from a geqdsk file, the data is saved already because we save the geqdsk file, but it might be nice to save the wall points in a more accessible form in the grid file - can be useful for analysis and post-processing.
String outputs, like parallel_transform
, hypnotoad_inputs
and hypnotoad_git_hash
should be written as global attributes so that BOUT++ can read them with Mesh::get()
. That is required for consistency with IDL hypnotoad's grid files too.
This needs 'global' (or 'file-level') attribute support in boututils.datafile.DataFile
(to avoid horrible hacks at least).
Following discussion with H.Seto, it would be useful for post-processing if dy was defined so that y went from 0 to 2pi in the core region of tokamak grids. Is there a way to do this, while allowing for cases like Torpex where there isn't a core region?
STORM gets nxpe=-2147483647 and crashes. I suppose it comes from 'default _FillValue of -2147483647 used'. Although
ds0['var'][:]
etc. correctly.
Would be nice if hypnotoad2 was structured better and pip-installable. Todo:
*.py
files under a hypnotoad2
subdirectory setup.py
(including an entry_point
for anything that should be executable)@ZedThree @bendudson please feel free to expand the list above with anything I've missed!
The implementation of the spacing functions (EquilibriumRegion.combineSfuncs()
, etc.) has evolved into something horribly tangled. I think one of the uses has combineSfuncs()
call fixedSpacingFunc()
call combineSfuncs()
with different arguments or something horrible like that. The whole lot could do with refactoring.
It would be nice if examples/tokamak
generated a geqdsk file from it's analytical psi-function, which could then be used with hypnotoad-gui
or hypnotoad_geqdsk
to create a grid file. Working with a geqsk file would demonstrate the typical workflow (the example was written before those interfaces existed!).
It would be nice to have the option (a check box maybe?) to plot the psi contours in the GUI with normalised psi rather than the dimensional psi. This would make it easier to pick psinorm_*
values.
It would be nice to have an interface (maybe even graphical?) that makes it easier to prototype/experiment when creating an input file than just passing input file names to a command line script like hypnotoad2_geqdsk experimental_equilib.g my_grid.yml
.
There are already plotting functions which could be used to provide output.
Possible features:
nx
and finecontour_Nfine
, and possibly some looser atol
s) which would make iterating on the original grid quicker.TokamakEquilibrium.default_options
and provide some sort of browser where the user could see the current and default settings for all options, see help/description, and modify the values. Done in #17Mesh.geometry()
output for the prototype?)..yml
file with the final settings, and generate a grid-file from it. Done in #17.
xBOUT
to help plotting the final results?.yml
input file, to prototype changes to it interactively. Done in #17.We could probably achieve quite a bit of this quickly by providing methods/functions that could be called at the Python interactive prompt. Maybe a template Jupyter notebook containing a suggested grid-generation workflow. A hypnotoad1-like gui interface would be the nicest option... GUI added in #17 thanks to @ZedThree! Some extras for the gui that would be nice to have:
There are some unit tests for the core PsiContour
, EquilibriumRegion
, MeshRegion
, Mesh
components, but I (@johnomotani) don't think it's as complete as I would like.
Also would be nice to test/check the expressions implemented for metric coefficients, etc. Is it possible to provide a set of analytic inputs for which the metric components, curvature, etc. can be calculated exactly and check against them? Most of the expressions should only depend on the finecontour_Nfine
and finecontour_atol
parameters, which can influence the approximation to the y-coordinate, but should be otherwise independent of grid resolution. A few expressions (e.g. the curvature) do depend on grid resolution, and we could check the convergence.
In principle hypnotoad2 is embarassingly parallelisable. The most expensive part tends to be refining the FineContour
s (at least when finecontour_Nfine
is large), and every FineContour
is independent. However, functions are not pickle-able which I think makes using multiprocessing
tricky. There might be workarounds for this though https://medium.com/@emlynoregan/serialising-all-the-functions-in-python-cd880a63b591.
Other parts of the code could be parallelised, though it might not be worth it as probably they do not typically take long anyway. For example most if not all of the output fields (metric coefficients, etc.) are independent and could be calculated simultaneously. dask
might be able to do this with minimal changes (possibly convert arrays to dask arrays, and then do
g11, g22, g33, ... = dask.compute(g11, g22, ...)
just before writing them out.
As discussed here #25 (comment) there are various issues with using the options
module for handling settings in hypnotoad
:
options
allows getting options simply as e.g. self.options.orthogonal
, but "that is only a few lines [to implement], I [@dschwoerer] did that to drop the dependency on Bunch."deepcopy
A replacement Options
class would be welcome. Maybe a possibility for something shared with xBOUT
boutproject/xBOUT#94 boutproject/xBOUT#97?
There's an equilibrium
IMAS data structure that would be nice to support: https://gafusion.github.io/omas/schema/schema_equilibrium.html
It's a schema rather than a file format, so it would be possible to read in JSON, hdf5, etc as long as they matched the schema.
Unfortunately I don't have access to any better documentation than the OMAS version of the schema.
It would be nice to add a UUID to grid files (compare boutproject/BOUT-dev#2149) which BOUT++ could then read and save to output, to verify that a simulation used a certain grid file.
Need some documentation.
At least:
.yaml
input files doWould be nice to have:
sphinx-argparse
to document the options and provide help and usage instructions.Having all of the build config in pyproject.toml
is now well supported, and now even editable installs work without setup.py
since pip 22
. PEP 621 defines some standard keys, so people can use new and weird build tools like poetry or flit if they like.
I'm happy to implement this if it would be useful!
At the moment zShift
is calculated in MeshRegion.calcZShift()
by integrating on the PsiContour
s (integrating in y
). It would be nicer to integrate on FineContour
s (as is done for the poloidal distance) and then interpolate to the final grid positions, because then zShift
would be more accurate (as long as Nfine
is large), and also zShift
and shiftAngle
would be guaranteed to be consistent when the y
-resolution is changed.
The current algorithm for defining poloidal spacing for nonorthogonal grids is not particularly robust, and requires a significant amount of manual tweaking to produce a good grid. An improved method would be very nice!
The current algorithm defines a 'spacing function' for each PsiContour
independently. The parameters of the spacing functions vary in a smooth way radially in order to create a sensible grid. This method was chosen in large part because it was convenient to implement.
Now that there are the FineContour
objects (which are indepedent of the PsiContour
poloidal spacing) providing the underlying skeleton for the grid, and there is the regrid()
functionality, it would be possible to implement other algorithms. PsiContour.getRegridded()
could easily be modified to accept an array of poloidal positions instead of a spacing function, by modifying this block
hypnotoad/hypnotoad/core/equilibrium.py
Lines 1678 to 1686 in b7ec7d0
s
is taken from the array passed in instead of calculated from sfunc
. Then it would be possible to do some sort of iteration (pseudo-timestepping?) on the array of poloidal positions.
For example, given an array of poloidal positions:
MeshRegion.distributePointsNonorthogonal()
to get the R-Z positions...and iterate until a relaxed state is found. To control the grid spacing and deal with non-orthogonal features of the grid (like target plates) it would probably be necessary to have some parameters that adjust the 'forces' depending on position in the grid:
nonorthogonal_*_poloidal_spacing_length
.nonorthogonal_*_poloidal_spacing_range*
parameters?If implementing this suggestion, it would probably be a good idea to parallelise MeshRegion.distributePointsNonorthogonal()
. The reason this method was not parallelised before was to avoid having to construct sfunc_orthogonal_list
on the parallel workers (have to construct on the workers because functions cannot be serialised by dill
to be communicated), but the 'orthogonal spacing function' would not be required in the new method.
As another possible speed-up, it should probably be OK to skip the PsiContour.refine()
calls until the iteration is nearly converged, as the interpolation from FineContour
objects should be pretty accurate.
As an extension of the above suggestion, with a more substantial refactoring of the code, it would be possible to allow the PsiContour
objects (for nonorthogonal grids) to extend between (what are currently) different regions - i.e. a single PsiContour
object would extend from target to target in the SOL or PFRs, or all the way around the core. Then even the poloidal boundaries between regions could be allowed to move, which might be useful for some configurations (e.g. where the divertor legs are very short so the X-point is close to the wall).
Possibly the region boundaries could be updated in a different way, with the structure kept more like it is at present but with the boundaries being moved. The advantage of the suggestion above (compared to this one) is that the FineContour
objects would extend from target to target, etc. and so would not need to be changed when the region boundaries move.
The IDL hypnotoad created density and temperature profiles from the equilibrium. Should we add a feature to create them? Do eqdsk files always provide pressure profiles?
Would it be a good idea when creating a grid file from a geqdsk equilibrium file to save the entire geqdsk file into the grid file, e.g. as a massive string? Pro: ensures the geqdsk file can be recovered. Con: grid file is a bit bigger.
Stupid question, but wouldn't hypnotoad be a better name?
As far as I understand, this is supposed to do basically the same thing as the old hypnotoad (more or less). So a user wouldn't really care whether this is an improved version or a rewrite, it is basically version 2 of hypnotoad.
Thinking from the user perspective, I want hypnotoad, thus I install hypnotoad. Whether that is version 1 or 2 (or 3) doesn't matter that much. Thus I can just pip install hypnotoad
and get the best (newest) version.
https://pypi.org/project/hypnotoad/ is still available ๐
Parameterised, analytic equilibria can be created following the recipe in [Cerfon&Freidberg (2010)]. There is already a Python implementation https://github.com/johnomotani/CerfonFreidbergGeometry (although it could do with a few cosmetic upgrades). It would be nice to add a new tab to the hypnotoad GUI which could allow a user to tweak the parameters of the analytic equilibrium and save them into an input .yml
file. Then the Psi
function from CerfonFreidberg
could be passed to TokamakEquilibrium
(which should only need a small upgrade to TokamakEquilibrium
), allowing hypnotoad to grid the analytical equilibrium.
Edit (updating comment below): Should note the health warning with these analytic equilibria - the equilibrium implies a pressure profile, which will generally not be consistent with a real machine or with the plasma solution produced by your code. Outside the separatrix things are probably even more dodgy - there's an analytic form for psi, but it assumes that the pressure is a linear function of psi, which is not realistic as in the SOL pressure is (a) not a flux function and (b) should drop quickly to ~0 and cannot (physically) be negative...
Can we modify the coordinate system slightly, so that the Jacobian is always positive?
BOUT++ currently rejects inputs with negative Jacobians, but this is what happens when the poloidal field is negative.
In https://bout-dev.readthedocs.io/en/latest/user_docs/coordinates.html can we just remove the factor of sigma (sign of Bpol) from the definition of Z? This would reverse the sign of g^xz and g^yz, change some elements of g.. and mean that J was always positive. It would also mean that:
There are now several methods for refining points: line
, newton
, integrate
, integrate+newton
.
Only line
is tested in test_equilbrium.py
, and using other methods sometimes fails where line
passes. I suspect this is because the tests start with points very far from the contour, and were set up in such a way that line
would find the right contour, so this does not indicate a problem with the other methods. The failure of integrate
may just be a question of slightly too tight tolerance (only fails test_refine
), and integrate+newton
fails to converge, but only on the same test. newton
fails to converge on several tests.
Hi. I have been trying to create a grid using the tokamak example provided. I can get the visual representation of the grid but the file created seems to be incomplete as I get the following error
DataFile: None passed as data to write. Ignoring
DataFile: None passed as data to write. Ignoring
I have tried to use the incomplete file in a simulation, and that also comes up with errors
Is there any way of using the tokamak example script to create a usable grid file?
In the temporaryExtend()
method used to extend a PsiContour
hypnotoad/hypnotoad/core/equilibrium.py
Line 1802 in 4cef82a
hypnotoad/hypnotoad/cases/tokamak.py
Lines 615 to 623 in 4cef82a
Trying to change the value of a string-type option in the GUI causes a crash. Can work around by setting in an input file and loading that.
total(dy) = 10.77, not 6.28.
# constant spacing in y for now if self.ny_core > 0: # If there is a core region, set dy consistent with 0<=y<2pi in the core self.dy_scalar = 2.0 * numpy.pi / self.ny_core else: # No core region, set dy consistent with 0<=y<2pi in whole domain self.dy_scalar = 2.0 * numpy.pi / self.ny_noguards
For my test ny_... = 8/24/8/12/32/16, dy should be: 2np.pi/96=0.065.
But grid['dy']=0.1122. It seems only to count the outer half, 2np.pi/(16*2+32)=0.1122.
GEQDSK equilibrium files come in different flavours, with different definitions of poloidal flux (see PR #172). The files should also include the safety factor, that can be checked once the grid has been generated.
When parallel execution is enabled, hypnotoad often (always?) hangs when the program finishes, and needs to be terminated with ^C.
It seems there must be somehow a circular reference somewhere, maybe between Mesh
and its ParallelMap
member variable?
Edit: Actually the __del__()
methods do (at least sometimes) get called after a keyboard interrupt. Maybe that suggests the hang is somewhere else? Unless the interrupt somehow breaks some circular reference chain and lets the garbage collection gets started??
Note: this 'hang' happens after grid generation is finished and the grid file is closed, so it should not cause any errors.
hypnotoad2: hypnotoad2_geqdsk mast.geqdsk
nx = 65, ny = 65
102
Options
=======
Name | Value
--------------------------------------------------------------------------------
cap_Bp_ylow_xpoint | False (default)
curvature_type | curl(b/B) with x-y derivatives (default)
finecontour_Nfine | 100 (default)
finecontour_atol | 1e-12 (default)
finecontour_diagnose | False (default)
finecontour_maxits | 200 (default)
follow_perpendicular_atol | 1e-08 (default)
follow_perpendicular_rtol | 2e-08 (default)
geometry_rtol | 1e-10 (default)
nonorthogonal_radial_range_power | 1.0 (default)
nonorthogonal_spacing_method | combined (default)
nonorthogonal_target_poloidal_spacing_length | None (default)
nonorthogonal_target_poloidal_spacing_range | None (default)
nonorthogonal_target_poloidal_spacing_range_inner | None (default)
nonorthogonal_target_poloidal_spacing_range_outer | None (default)
nonorthogonal_xpoint_poloidal_spacing_length | 0.05 (default)
nonorthogonal_xpoint_poloidal_spacing_range | None (default)
nonorthogonal_xpoint_poloidal_spacing_range_inner | None (default)
nonorthogonal_xpoint_poloidal_spacing_range_outer | None (default)
nx_core | 5 (default)
nx_pf | 5
nx_pf_lower | None (default)
nx_pf_upper | None (default)
nx_sol | 5 (default)
nx_sol_inner | 5
nx_sol_outer | 5
ny_inner_divertor | 4 (default)
ny_inner_lower_divertor | 4
ny_inner_sol | 4
ny_inner_upper_divertor | 4
ny_outer_divertor | 4 (default)
ny_outer_lower_divertor | 4
ny_outer_sol | 4
ny_outer_upper_divertor | 4
ny_sol | 8 (default)
orthogonal | True (default)
poloidal_spacing_delta_psi | 0.00125012279304738
poloidal_spacing_method | sqrt (default)
poloidalfunction_diagnose | False (default)
psi_core | -0.11251105137437345
psi_pf_lower | -0.11251105137437345
psi_pf_upper | -0.11251105137437345
psi_sol | -0.13751350723532105
psi_sol_inner | -0.13751350723532105
psi_spacing_separatrix_multiplier | None (default)
psinorm_core | 0.9 (default)
psinorm_pf | 0.9
psinorm_pf_lower | 0.9
psinorm_pf_upper | 0.9
psinorm_sol | 1.1 (default)
psinorm_sol_inner | 1.1
refine_atol | 2e-08 (default)
refine_methods | integrate+newton, integrate (default)
refine_width | 0.01 (default)
sfunc_checktol | 1e-13 (default)
shiftedmetric | True (default)
target_poloidal_spacing_length | None (default)
xpoint_poloidal_spacing_length | 0.05 (default)
y_boundary_guards | 0 (default)
Traceback (most recent call last):
File "/home/peter/Codes/hypnotoad2/hypnotoad_test_venv/bin/hypnotoad2_geqdsk", line 11, in <module>
load_entry_point('hypnotoad2', 'console_scripts', 'hypnotoad2_geqdsk')()
File "/home/peter/Codes/hypnotoad2/hypnotoad2/scripts/hypnotoad2_geqdsk.py", line 32, in main
eq = tokamak.read_geqdsk(fh, options=options)
File "/home/peter/Codes/hypnotoad2/hypnotoad2/cases/tokamak.py", line 1521, in read_geqdsk
**kwargs
File "/home/peter/Codes/hypnotoad2/hypnotoad2/cases/tokamak.py", line 236, in __init__
self.makeRegions()
File "/home/peter/Codes/hypnotoad2/hypnotoad2/cases/tokamak.py", line 489, in makeRegions
leg_regions, core_regions, segments, connections = self.describeDoubleNull()
File "/home/peter/Codes/hypnotoad2/hypnotoad2/cases/tokamak.py", line 722, in describeDoubleNull
lower_legs = self.findLegs(lower_x_point)
File "/home/peter/Codes/hypnotoad2/hypnotoad2/cases/tokamak.py", line 323, in findLegs
intersect = self.wallIntersection(Point2D(*pos), Point2D(*newpos))
File "/home/peter/Codes/hypnotoad2/hypnotoad2/core/equilibrium.py", line 2967, in wallIntersection
closed_wall = self.wall + [self.wall[0]]
IndexError: list index out of range
This is with a GEQDSK file generated by freegs from the 03-mast.py
example (attached, ignore the .log
extension that's just so github will let me upload it!)
mast.geqdsk.log
At the moment the supported geometries for tokamak grids are single-null and double-null and must include one or two X-points. It would be nice to have more options:
psinorm_sol < 1
then the separatrix is outside the requested region. Instead of using the separatrix as the base contour use some closed contour (not sure whether the psi_inner
, psi_outer
or 0.5*(psi_inner + psi_outer)
would be best)The poloidal spacing variable hy
corresponds to hthe
in the original Hypnotoad, but is defined slightly differently for non-orthogonal grids. For that reason, I named the variable differently, and the variable in the netCDF output files is named hy
.
The downside of the current implementation is that existing codes may calculate metric coefficients using hthe
as input. This can be useful as normalisation can be simpler on basic R
and hy
(lengths) and B
, Bt
, Bp
(magnetic fields) than on metric coefficients (when psi
is used as radial coordinate lengths and magnetic field units get mixed up in the coordinate system).
The 'problem' with changed definition of hy
vs. hthe
only affects non-orthogonal grids. In practice, I guess there are no production codes depending on the Hypnotoad-1 style non-orthogonal grids, so it is probably not an issue to save hthe
to the grid files, because in practice no one is depending on the old definition. On the other hand, saving as hthe
provides better backward-compatibility with codes using orthogonal grids.
So I'd propose to update hypnotoad
to save the variable as hthe
. Thoughts @bendudson @ZedThree @bshanahan?
As the title suggests - the GUI closes if "finecontour_extend_prefactor" is changed. Doing the same non-interactively produces no issues.
The options are converted to a string here
hypnotoad/hypnotoad/core/equilibrium.py
Lines 3509 to 3523 in b3f3182
It seems like this method should have been changed when the options were refactored - there is now only self.user_options
, not separate self.equilibOptions
and self.user_options
. The parts on l.3515-3519 can probably be deleted now.
Ideally, this method should be reversible to produce a dict
equivalent to user_options
. We could test that by checking with a test Mesh
something like:
assert dict_equiv(dict(mesh.user_options), yaml.load(mesh._getOptionsAsString())
I think this isn't a serious bug, as the only effect should be that the options all get printed out twice at the moment - the information should all be there though.
change the plot options in the preference tab would make the GUI crash, the error message:
Traceback (most recent call last):
File "/projects/physics/SOLTransport/repos_eric/hyp_env/lib/python3.9/site-packages/hypnotoad/gui/gui.py", line 578, in accept
self.parent.gui_options.set(
AttributeError: 'dict' object has no attribute 'set'
Aborted
The troubleshooting information from the wiki (https://github.com/boutproject/hypnotoad/wiki) has now been included in the manual (sections https://hypnotoad.readthedocs.io/en/stable/tips-and-tricks.html and https://hypnotoad.readthedocs.io/en/stable/nonorthogonal-tips.html). It's probably not good to have multiple places for information - it's harder to search and harder to keep up to date. Options:
Any preferences or other options? I'd probably vote for 1 because having more than one place to look for stuff is bad.
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.