To solve the problem I created some function to help visualize the placement and statistics of the disks. For each functions disks is a list with elements {radius, {xCenter, yCenter}} and boundary is a vector {width, height} describing the bounding area, which is centered at the origin.
areaCoverage calculates the percent of the enclosed area covered by particles.
raiusStats calculates relevant statistics of the disk radii.
visualizeLayer creates a graphic with the disks and bounding area, and gives a list of any disks that intersect each other or the boundary.
areaCoverage[disks_, boundary_] := Module[
{diskArea, boundaryArea},
diskArea = Pi*Total[disks[[All, 1]]^2];
boundaryArea = Times @@ boundary;
N[diskArea/boundaryArea*100]
];
radiusStats[disks_] := Module[
{radii},
radii = disks[[All, 1]] ;
N[ {Mean[radii], StandardDeviation[radii] } ]
];
visualizeLayer[disks_, boundary_] := Module[
{d, b, pairs, intersecting, bInt},
b = Rectangle[ -boundary/2, boundary/2 ];
d = Table[Disk[disk[[2]], disk[[1]] ], {disk, disks}];
pairs = Subsets[d, {2} ];
pairs = Table[With[{
intersect = (RegionMeasure@RegionIntersection@pair != 0)
},
{pair, intersect}
],
{pair, pairs}
];
intersecting = Select[pairs, #[[2]] == True &][[All, 1]];
bInt = Table[With[{
intersect = ! (RegionUnion@{b, disk} === b)
},
{disk, intersect}
],
{disk, d}
];
bInt = Select[bInt, #[[2]] == True &][[All, 1]];
{Show[Graphics[ {FaceForm[], EdgeForm[Black], b} ], d // Graphics,
ImageSize -> 500], intersecting, bInt}
];
I started with a list of three disks, adding new ones one-by-one playing with the parameters and placement to match the statistics I wanted.
While not automated, these functions certainly helped create scenarios more quickly than would otherwise be possible. The visualization of the particles made adding new ones quite easy, and most of the time was spent making small adjustments to match the statistics to given values.
Here is a minimum set of data:
boundary = {200, 200};
disks={
{ 10, {0, 0} },
{ 10, { 50, 50 } },
{ 10, {-50, -50} },
{ 20, {-40, -50} },
{ 30, {-80, 0} }
};
RegionDisjoint. See the 'Neat Example' in the documentation here. – Greg Hurst Oct 06 '17 at 17:42RegionUnionfor checking with the boundary intersection because it also works if a disk is completely outside the region.I provided a minimum example of data as a comment in the answer.
– bicarlsen Oct 06 '17 at 20:24