Nature is an inexhaustible source of ideas for mathematicians. I was interested in the structure of pores some mushrooms, which looks very "geometrical". And at first sight can be easily explained.​​
​​In fact, it was not easy to model it. Here is a possible and convincing method, which also allows to generate a lot of different nature-like structures​​

Previous approaches

Poisson disk + Lloyd relaxation

In previous post, was proposed an algorithm for the distribution of points on area, that gave results very similar to the distribution of pores. Both visually and statistically. It is based on Poisson disk sampling with the following few steps of Lloyd relaxation. But such approach is purely descriptive. It reproduces the result well, but obviously the mushroom pores do not arise as a selection of random samples.

Turing patterns as PDES solution

I was told that these structures are very similar to Turing patterns, that are often found in the nature. A simple model is known, consisting of only two PDEs and four parameters, which implements the chemical process that leads to the formation of such structures. This model is implemented in Wolfram Documentation. I wrote my code, and with the given parameters we get patterns that are very similar to pores picture.
Clear[solTuring];​​solTuring[(*Diffusionparameters*)du_,dv_,​​(*Reactionparameters*)f_,k_,​​(*Maxtime*)T_,(*Gridsize*)size_]:=Module[{u,v,t,x,y,​​eqs,bndConds,initConds,initReg,rndInit,sol},​​​​eqs={D[u[t,x,y],t]==duLaplacian[u[t,x,y],{x,y}]-u[t,x,y]*v[t,x,y]^2+f(1-u[t,x,y]),D[v[t,x,y],t]==dvLaplacian[v[t,x,y],{x,y}]+u[t,x,y]*v[t,x,y]^2-(f+k)v[t,x,y]};​​​​bndConds={u[t,0.,y]==u[t,size,y],u[t,x,0.]==u[t,x,size],v[t,0.,y]==v[t,size,y],v[t,x,0.]==v[t,x,size]};​​​​initReg=0.16size<x<0.96size&&0.16size<y<0.96size;​​​​rndInit[c_,r_,s_,num_,initReg_,def_]:=Interpolation[Flatten[Table[{x,y,Piecewise[{{RandomReal[{c+r,c-r}],initReg}},def]},{x,0,s,s/num},{y,0,s,s/num}],1],InterpolationOrder->0];​​​​initConds={u[0.,x,y]==rndInit[0.5,0.05,size,100,initReg,1.][x,y],v[0.,x,y]==rndInit[0.25,0.05,size,100,initReg,0.][x,y]};​​​​sol=Quiet@NDSolve[Join[eqs,bndConds,initConds],​​{u,v},{t,0,T},{x,0.,size},{y,0.,size},Method->{"MethodOfLines","SpatialDiscretization"->{"TensorProductGrid","MaxPoints"->100,"MinPoints"->100,"DifferenceOrder"->2}}];​​{u,v}/.First@sol​​];
Next evaluation takes ~10 sec on general PC
In[]:=
res=solTuring[0.00031,0.000047,0.03,0.0635,20000,3.1]
Result:
In[]:=
ContourPlot[res[[2]][19900,x,y],{x,0,3.1},{y,0,3.1},PlotRange->All,Contours->6]
Out[]=
However, there are problems:
◼
  • The resulting structure is very strongly and sharply dependent on the values of the parameters.
    Both the parameters of the equation system itself and the settings of the solution method.
    It is very difficult to explore the options.
  • ◼
  • I don’t know how to get thousands of pores for statistics in a reasonable time
  • ◼
  • This system is a mathematical model of chemical reaction. Although biochemistry is certainly relevant to the formation of pores, in fact their formation - process in biological tissue, defined by cell division, fabric elasticity, etc.
  • Cellular automata

    Here is proposed the implementation of the algorithm from the article as a cellular automaton. Unfortunately, it also works long enough and is sensitive to parameters. I tried to get Turing patterns with classical CA, but so far without success. Maybe later it will work.

    Relaxation in potential

    Definition of potential

    Among many others, the model of pores as particles interacting with a certain potential energy proved to be very suitable. The form of potential must take into account that biological tissue resists both compression and stretching. The analysis of real pores shows that there is a certain average distance at which they stabilize. This fact describes well the classical two-power potential
    U(r)=α
    p
    1
    r
    +
    p
    2
    r
    If the following conditions are satisfied:
    p
    1
    >
    p
    2
    &&
    p
    2
    α
    p
    1
    <0
    than we have energy minimum in
    r
    min
    =
    1
    p
    1
    -
    p
    2
    -
    p
    2
    α
    p
    1
    And conversely, if we set the desired average distance δ between pores and powers of potential, we can calculate the appropriate coefficient:
    α=-
    p
    2
    p
    1
    p
    2
    -
    p
    1
    δ
    In[]:=
    Clear[energy,coreDist,getCoeff];​​energy[pt_,pts_,α_,pow1_,pow2_]:=Total[(α
    pow1
    #
    +
    pow2
    #
    )&/@(EuclideanDistance[pt,#]&/@pts)];​​​​coreDist[α_,p1_,p2_]:=​​If!PossibleZeroQ@p1&&!PossibleZeroQ@p2&&p1>p2&&p2αp1<0,​​
    1
    p1-p2
    -p2
    αp1
    ,None;​​​​getCoeff[δ_,p1_,p2_]:=​​If!PossibleZeroQ@p1&&!PossibleZeroQ@p2&&p1>p2,​​
    -p2
    p1
    p2-p1
    δ
    ,None;
    Clear[a,p1,p2,d];​​Manipulate​​a=getCoeff[d,p1,p2];​​PanelIfNumberQ@a,​​Plota
    p1
    x
    +
    p2
    x
    ,{x,0,1},PlotRange->{a
    p1
    d
    +
    p2
    d
    ,15},​​Filling->Axis,PlotLabel->d,PlotHighlighting->None​​,​​Style["Invalid parameters",Bold,13]​​,ImageSize->{300,250}​​,{{p1,-2.8},-5.,5.,0.01},{{p2,-2.95},-5.,5.,0.01},​​{{d,0.1},0.001,0.5,0.001},{{a,{}},ControlType->None},​​SaveDefinitions->True​​
    Out[]=
    ​
    p1
    p2
    d

    Relaxation method

    In serious studies of many particle systems, complex, smart algorithms are used. Some of them are optional with the built-in NMinimize. But first of all, I doubt that mushrooms use anything like this =)
    Second, it requires a lot of computing resources.
    I stopped at the simplest, natural approach:
    In the small disk surrounding each pore, select a small number of samples and pore moves to a point that realizes the minimum potential energy among them.

    Additional considerations

    Pores are not given immediately, in full quantity. They appear as the fungus grows in those places where there is not yet. And of course there is no long-range interaction. The relaxation of their positions occurs as a result of an elastic reaction of the mushroom tissue between adjacent pores. To obtain more natural results, we perform several steps of relaxation between the birth of new pores.

    Final module

    Graphics

    Evaluation

    We start with a small number of randomly distributed pores:
    If possible, it is advisable to run parallel computations:
    Set parameters and validation.
    ​Input format:
    {"Number of neighbors",
    "Number of test samples",
    "Radius of disk for samples",
    "Supposed average distance",
    "First energy power",
    "Second energy power",
    "Rate of new pores per step",
    "Number of relaxation steps"}
    It is better to carry out iterations in small portions, so you can plan your calculation time (on average for 6 cores the first 20 iterations takes ~10 sec, but with increasing number of pores time grows). And change the parameters on the fly, getting even more interesting results.

    Some examples

    By changing parameters (including during iterations) you can get a huge number of different structures. It is important that the dependence on parameters is not critical and patterns smoothly pass from one to another.
    ◼
  • Preset 1
    ​Typical tinder polypore pattern
  • ◼
  • Preset 2
  • ◼
  • Preset 3
  • ◼
  • Preset 4​
    Frequently observed Turing patterns
  • ◼
  • Preset 5
  • CITE THIS NOTEBOOK

    Fungi pores pattern: final approach​
    by Denis Ivanov​
    Wolfram Community, STAFF PICKS, June 17, 2025
    ​https://community.wolfram.com/groups/-/m/t/3480611