{"id":18625669,"url":"https://github.com/urbainvaes/cahn-hilliard","last_synced_at":"2026-02-23T08:34:28.674Z","repository":{"id":93071667,"uuid":"59561222","full_name":"urbainvaes/cahn-hilliard","owner":"urbainvaes","description":"Code to simulate the Cahn-Hilliard equation","archived":false,"fork":false,"pushed_at":"2019-05-10T21:38:02.000Z","size":18947,"stargazers_count":20,"open_issues_count":2,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-27T15:43:22.755Z","etag":null,"topics":["finite-element-analysis","freefem","gmsh","simulation"],"latest_commit_sha":null,"homepage":"","language":"GLSL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/urbainvaes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-05-24T09:51:09.000Z","updated_at":"2025-08-10T23:03:29.000Z","dependencies_parsed_at":"2023-04-28T20:32:31.620Z","dependency_job_id":null,"html_url":"https://github.com/urbainvaes/cahn-hilliard","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/urbainvaes/cahn-hilliard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urbainvaes%2Fcahn-hilliard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urbainvaes%2Fcahn-hilliard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urbainvaes%2Fcahn-hilliard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urbainvaes%2Fcahn-hilliard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urbainvaes","download_url":"https://codeload.github.com/urbainvaes/cahn-hilliard/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urbainvaes%2Fcahn-hilliard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29740026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T07:44:07.782Z","status":"ssl_error","status_checked_at":"2026-02-23T07:44:07.432Z","response_time":90,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["finite-element-analysis","freefem","gmsh","simulation"],"created_at":"2024-11-07T04:35:37.478Z","updated_at":"2026-02-23T08:34:28.625Z","avatar_url":"https://github.com/urbainvaes.png","language":"GLSL","funding_links":[],"categories":[],"sub_categories":[],"readme":"OUTDATED\n\n# Cahn-Hilliard solver\nThis repository contains the code we developped to simulate the Cahn-Hilliard equation in 2 and 3 dimensions.\n\n## Dependencies\nThis code depends on the following free and open-source programs:\n\n- **Gmsh**, to generate the mesh and do the post-processing;\n- **FreeFem++**, to solve the PDE numerically;\n- **Paraview**, to visualize results;\n- **Gnuplot**, to produce plots;\n- **GNU Make**, to build the project;\n- **cpp**, to configure the solver.\n\n## Installation\nTo code of the project can be obtained by cloning the git repository.\n\n`git clone https://github.com/urbainvaes/cahn-hilliard`\n\n## Getting started\nA simulation is defined by three elements:\n\n- A **geometry**, which must be described by a Gmsh .geo file.\n- A **problem configuration**, which must be written in the FreeFem++ language,\n    and specifies the initial and boundary conditions of the problem,\n    based on the physical labels defined in the **geometry**.\n    In addition, this file can be used to specify the physical parameters of the problem (interface thickness, mobility, etc.)\n    and the parameters of the solver (value of time step, number of steps).\n    If left undefined, default parameters are used.\n- A **post-processing file**, which produces pictures or videos from the output produced by the solver.\n\n### Creating a new simulation\nBelow, we describe step by step how to create a simple simulation for the coalescence of two droplets in 2D, which we name *example-droplets*.\n\nThe first step is to create the directory *inputs/example-droplets* (`mkdir -p inputs/example-droplets`).\nand to define each of the elements above.\n\n- For the **geometry**, we create a file *square.geo* in the newly created directory.\n  This file defines a simple square, assigns the label 1 to the domain, and the labels 1,2,3,4 to the boundaries.\n\n```\n// Dimensions of square\nLx = 1;\nLy = 1;\n\n// Mesh size;\ns = .01;\n\nPoint(1) = {0,  0,  0, s};\nPoint(2) = {Lx, 0,  0, s};\nPoint(3) = {Lx, Ly, 0, s};\nPoint(4) = {0,  Ly, 0, s};\n\nLine(1) = {1,2};\nLine(2) = {2,3};\nLine(3) = {3,4};\nLine(4) = {4,1};\n\nLine Loop(1) = {1,2,3,4};\nPlane Surface(1) = {1};\n\nPhysical Surface (1) = {1};\nPhysical Line (1) = {1};\nPhysical Line (2) = {2};\nPhysical Line (3) = {3};\nPhysical Line (4) = {4};\n\n// View options\nGeometry.LabelType = 2;\nGeometry.Lines = 1;\nGeometry.LineNumbers = 2;\nGeometry.Surfaces = 1;\nGeometry.SurfaceNumbers = 2;\n```\n- Next, we write the **problem configuration** in a file *coalescence.pde*, in the same directory.\n  This file must define initial and boundary conditions.\n```\n// Initial condition\nreal radius = 0.2;\n\nreal x1 = 0.5 + radius*1.1;\nreal y1 = 0.5;\nfunc droplet1 = ((x - x1)^2 + (y - y1)^2 \u003c radius^2 ? 1.5 : -0.5);\n\nreal x2 = 0.5 - radius*1.1;\nreal y2 = 0.5;\nfunc droplet2 = ((x - x2)^2 + (y - y2)^2 \u003c radius^2 ? 1.5 : -0.5);\n\nfunc phi0 = droplet1 + droplet2;\nfunc mu0 = 0;\n[phi, mu] = [phi0, mu0];\n\n// Boundary conditions (Hydrophobic boundaries)\nvarf varBoundary([phi1,mu1], [phi2,mu2]) =\n  int2d(Th,1,2,3,4) (-5*mu2)\n;\n\n// Value of epsilon\neps = 0.04;\n\n// Time step\ndt = 1 * 1e-6;\n\n// Number of iterations\nnIter = 400;\n```\n- The program used for visualization in 2D is **paraview**, and so the view must be callable by pvpython.\n  The specification of this part is less flexible, and we recommend that you start by taking the following script.\n```python\n# Import modules\nimport re\nimport glob\nimport sys\nimport optparse\nfrom paraview.simple import *\n\n# Parse command line options\nparser = optparse.OptionParser()\nparser.add_option('-v', '--video', dest = 'file_video')\nparser.add_option('-i', '--input', dest = 'field_name')\nparser.add_option('-r', '--range', dest = 'range')\n(options, args) = parser.parse_args()\n\n# Ask for file name if undefined\nif options.field_name is None:\n    options.field_name = raw_input('Enter field name:')\n\n# Paraview code\nparaview.simple._DisableFirstRenderCameraReset()\n\n# Read data file\nfiles = sorted(glob.glob(\"output/\"+options.field_name+\".*.vtk\"), key=lambda x: int(x.split('.')[1]))\nscalarField = LegacyVTKReader(FileNames=files)\n\n# Retrieve name of scalar field\ncellData = str(scalarField.GetCellDataInformation().GetFieldData())\nlist_data_names = re.findall(r'Name: (.+)', cellData)\nlist_data_names.remove('Label')\ndata_name = list_data_names[0];\n\n# Animation\nanimationScene = GetAnimationScene()\nanimationScene.UpdateAnimationUsingDataTimeSteps()\n\n# Get active view and display scalar field in it\nrenderView = GetActiveViewOrCreate('RenderView')\ndisplay = Show(scalarField, renderView)\n\n# Set field to color\nColorBy(display, ('CELLS', data_name))\n\n# show color bar/color legend\ndisplay.SetScalarBarVisibility(renderView, True)\n\n# Set range\nif options.range is None:\n    display.RescaleTransferFunctionToDataRange(True)\nelse:\n    bounds = options.range.split(',')\n    scalarLUT = GetColorTransferFunction(data_name)\n    scalarLUT.RescaleTransferFunction(float(bounds[0]), float(bounds[1]))\n\n# reset view to fit data\nrenderView.ResetCamera()\n\n# Set representation type\n# display.SetRepresentationType('Surface With Edges')\ndisplay.SetRepresentationType('Surface')\n\n# Save video or play animation\nif options.file_video is not None:\n    WriteAnimation(options.file_video, Magnification=1, FrameRate=40.0, Compression=True)\nelse:\n    animationScene.Play()\n```\n\nTo finish specifying the problem, we must create a configuration file *config.mk* in the same directory,\nto specify that the geometry, problem, and post-processing are described by the files we created.\n```\nDIMENSION = 2               # Dimension of the problem\nGEOMETRY = square.geo       # File describing the geometry\nPROBLEM = coalescence.pde   # File describing the problem\nVIEW = view.py              # File used for post-processing\n```\n### Executing the simulation\nOnce all the elements of the simulation have been specified, it can be run.\nSince the folder *inputs* can contain the parameters for many simulations,\nthe first step is to specify that we want to run the *example-droplets* example.\nThis is done with the command `make install`, which creates the directory *tests/example-droplets*,\nwhich is where the different programs (gmsh, FreeFem++, gnuplot) will be executed,\nand where the outputs and temporary files will be stored.\n\nOnce this is done, we can proceed to create a mesh using `make mesh` and run FreeFem++ for the problem using `make run`.\nThe run generates output files in the directory *tests/example-droplets/output/*, which can be read by the file *view.py* to produce animation.\nOne can see the simulation results using `make visualization`, and create a video using `make video`.\n\n## Documentation\nThis section provides additional documentation about the code.\n\n### Targets of Makefile in top directory\nThe Makefile in the top directory of the project defines the following targets:\n- **install**: lists the simulations defined in inputs, prompts the user to select one and:\n\n    - Ensures that the directory *tests/simulation-name* exists, or creates it if necessary.\n    - Creates folders for the output, pictures and logs in the newly created directory, if necessary.\n    - Copies (using hard links) all the files from *inputs/simulation-name* and *sources* to the new directory.\n    - Creates a file *.problem* containing the name of the simulation in the root directory.\n\n- **uninstall**: removes the file *.problem*.\n- **clean-all**: removes the directory *tests*, which contains the outputs of all the simulations run.\n- **.DEFAULT**: when calling make with any other target than the three described above,\nGNU Make will pass the target to the *Makefile* in the subdirectory *tests/simulation-name*,\nwhere *simulation-name* is read from the file *.problem* created at installation.\n\n### Targets of Makefile in subdirectories\nBelow, **GEOMETRY**, **PROBLEM** and **VIEW** are the variables defined in the configuration file.\n- **mesh** : creates the file *output/mesh.msh* from the file **GEOMETRY**.\n- **run** : preprocess and execute *solver.pde* using FreeFem++, using the **PROBLEM**.\n- **visualization** : shows the simulation results in Paraview (2D) or Gmsh (3D) using the file **VIEW**.\n- **video** : same as **visualization**, but create a video from the frames.\n- **view** : view video using vlc.\n- **plots** : create plots of the physical quantities based on script in *sources/gnuplot/thermo.plt*.\n\n### Use predefined geometries and views\nIn the simple example above, we created new files for the geometry, the problem and the post-processing,\nand referred to these files for the configuration file *config.mk*.\nOften, however, one would like to use the same geometry or post-processing for different simulations.\nIn addition, this repository defines geometries in *sources/geometries* and views in *sources/views*.\nSince these two folders will both be copied to the simulation directory (*tests/simulation-name*),\nthey can be used for the simulation.\nFor example, instead of rewriting a *.geo* for a square, one could use the readily available file *sources/geometries/square.geo*,\nand refer to it from the configuration file.\nThe path to the file must be relative to the execution directory, i.e. we have to write\n```\nGEOMETRY = geometries/square.geo.\n```\n\n## Modules of the code\nSeveral modules can be activated to simulate more complicated models.\nTo activate a module, add a line \"MODULE = 1\" in *config.mk*.\nEach of the modules is described below\n\n### Module *adapt*\nThe use of this module activates mesh-adaptation.\n\nIn 2D, the *FreeFem++* built-in function `adaptmesh` is use,\nwith parameters `hmax = 0.1` and `hmin = hmax/64`.\n\nIn 3D, the metric field used for the adaptation is used using `mshmet`,\nwith parameters `hmax = 0.1` and `hmin = hmax/20`,\nafter which the adaptation is accomplished by *Tetgen* through the *FreeFem++* function `tetgreconstruction`.\n\nIn both cases,\nthe default values of `hmin` and `hmax` have been chosen based on a number of examples\nand usually provide good results,\nbut they can be changed if desired in the problem configuration file.\n\n### Module *PLOT*\nWhen activated, the solver will display a plot of the solution at each time step.\nNote that this slows down the simulation.\n\n### Module *SOLVER_NAVIER_STOKES*\nThis modules adds Navier-Stokes equations to the sytem of equations of the simulation.\nTo use this module, boundary conditions for the pressure and velocity fields have to be specified in the problem file.\n```\nvarf varUBoundary(u, test) = ...;\nvarf varVBoundary(v, test) = ...;\nvarf varPBoundary(p, test) = ...;\n```\nPhysical parameters can also be defined, and will take default values if not.\nThe different parameters, with default values, are defined below:\n\n- `Re` (default: 1) is the Reynolds number of the flow,\n  which is assumed to take a constant value across the two phases.\n- `Ca` (default: 1) is the capillary number.\n- `muGradPhi` (default: 1) is a parameter prescribing the discretization used for the capillary term.\n  Its value must be 1, to use the discretization `mu*grad(phi)`, or 0, to use `phi*grad(mu)`.\n\n### Module *ELECTRO* (unstable)\nUsing this requires the definition of\n\n- epsilonR1: relative permittivity in phase *phi = -1*.\n- epsilonR2: relative permittivity in phase *phi = 1*.\n\nWhen enabled, the system will be coupled to the Poisson equation for the electric potential,\nthrough the addition of an additional term in the free energy.\n\n### Module *GRAVITY* (unstable)\nUsing this requires the definition of\n\n- `rho1`: specific mass of phase *phi = -1*.\n- `rho2`: specific mass of phase *phi = 1*.\n- `gx`: x-component of the gravity vector.\n- `gy`: y-component of the gravity vector.\n- `gz`: In 3D, z-component of the gravity vector.\n\nWhen enabled, gravity will be added to the simulation.\n\n## Authors\nBenjamin Aymard started the project in October 2015, and Urbain Vaes joined in March 2016.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furbainvaes%2Fcahn-hilliard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furbainvaes%2Fcahn-hilliard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furbainvaes%2Fcahn-hilliard/lists"}