前面分享了自己编制的电极颗粒随机分布几何模型的生成工具:电池极片颗粒随机生成与可视化网页版工具Deepseek生成随机颗粒锂离子电池三维多孔电极COMSOL模型【可下载】用Deepseek做了一个随机生成锂离子电池二维多孔电极COMSOL模型但是,这是工具都很难实现低孔隙率的情况,一直在思考如何优化改进这个工具,今天用AI编制了二维圆形颗粒压缩密集堆积模拟工具,效果如下图所示:压缩后AI平台:kimi初始提示词:编辑一个html网页,实现二维圆形颗粒在一个矩形内密集堆积,用户可以输入矩形高H、宽L、颗粒最大和最小半径,目标孔隙率e、矩形压缩比β,边界保护层a。首先,在高为H、宽为L*(1+β)的矩形内生成随机位置和半径的颗粒,颗粒不重叠,孔隙率为e/(1-β)。然后移动最右侧的边,距离为L*β,迫使颗粒运动,颗粒与边界保持距离a,颗粒之间相互接触相互作用,实现密集堆积。过程调整:(1)压缩时,颗粒之间施加一个力,颗粒间距越小,力越大,使颗粒移动,整体密集化;(2)两侧边界都移动,压缩比平分;(3)改变参数输入时,使用缩放比例使画图时最大化显示;(4)边界保护层默认值设置为矩形高度的1/50,力作用范围默认值设置为1/10,同时增加输入框,可以输入正数或负数,调整这个两个参数,最终的边界保护层值为矩形高度的1/50+输入值,力作用范围值为高度的1/10+输入值;最终代码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>二维圆形颗粒密集堆积模拟</title><style>body{font-family:Arial,sans-serif;margin:20px;display:flex;flex-direction:column;align-items:center;background-color:#f5f5f5;}.container{display:flex;width:100%;justify-content:space-between;margin-bottom:20px;background-color:white;border-radius:10px;box-shadow:0010pxrgba(0,0,0,0.1);overflow:hidden;}.control-panel{padding:20px;width:300px;background-color:white;}.canvas-container{flex:1;margin-left:20px;background-color:white;padding:20px;}canvas{background-color:#f0f0f0;border-radius:5px;box-shadow:005pxrgba(0,0,0,0.1);}label{display:block;margin-bottom:8px;font-weight:bold;color:#333;}input{width:100%;padding:8px;margin-bottom:15px;border:1pxsolid#ddd;border-radius:4px;font-size:14px;}.button-group{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:20px;}button{padding:10px15px;background-color:#4CAF50;color:white;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:background-color0.3s;}button:hover{background-color:#45a049;}.status{margin-top:20px;padding:15px;background-color:#f8f8f8;border-radius:5px;box-shadow:005pxrgba(0,0,0,0.1);}.statusp{margin:5px0;}h1{color:#333;margin-bottom:20px;}h3{margin-top:0;color:#333;border-bottom:1pxsolid#ddd;padding-bottom:10px;}</style></head><body><h1>二维圆形颗粒密集堆积模拟</h1><divclass="container"><divclass="control-panel"><h3>参数设置</h3><labelfor="height">矩形高度H(px):</label><inputtype="number"id="height"value="400"min="100"max="1000"><labelfor="width">矩形宽度L(px):</label><inputtype="number"id="width"value="400"min="100"max="1000"><labelfor="minRadius">颗粒最小半径(px):</label><inputtype="number"id="minRadius"value="10"min="5"max="50"><labelfor="maxRadius">颗粒最大半径(px):</label><inputtype="number"id="maxRadius"value="30"min="10"max="100"><labelfor="porosity">目标孔隙率e(0-1):</label><inputtype="number"id="porosity"value="0.35"step="0.01"min="0"max="1"><labelfor="compression">压缩比β(0-1):</label><inputtype="number"id="compression"value="0.2"step="0.01"min="0"max="1"><labelfor="paddingAdjust">边界保护层调整值(px):</label><inputtype="number"id="paddingAdjust"value="0"min="-50"max="50"><labelfor="forceDistanceAdjust">力作用范围调整值(px):</label><inputtype="number"id="forceDistanceAdjust"value="0"min="-50"max="50"><labelfor="springConstant">弹性系数k:</label><inputtype="number"id="springConstant"value="0.1"step="0.01"min="0.01"max="1"><divclass="button-group"><buttonid="generate">生成初始配置</button><buttonid="animate">开始压缩</button><buttonid="save">保存数据</button><buttonid="reset">重置</button></div><divclass="status"><p>状态:准备就绪</p><p>颗粒数量:0</p><p>当前孔隙率:0</p><p>边界保护层:0</p><p>力作用范围:0</p></div></div><divclass="canvas-container"><canvasid="particleCanvas"></canvas></div></div><script>//获取DOM元素constcanvas=document.getElementById('particleCanvas');constctx=canvas.getContext('2d');constgenerateBtn=document.getElementById('generate');constanimateBtn=document.getElementById('animate');constsaveBtn=document.getElementById('save');constresetBtn=document.getElementById('reset');conststatusElement=document.querySelector('.status');//设置画布大小functionresizeCanvas(){canvas.width=document.querySelector('.canvas-container').offsetWidth-40;canvas.height=Math.min(600,window.innerHeight-200);}resizeCanvas();window.addEventListener('resize',resizeCanvas);//参数letparams={height:400,width:400,minRadius:10,maxRadius:30,porosity:0.35,compression:0.2,padding:8,springConstant:0.1,forceDistance:40,expandedWidth:0,targetWidth:0};//粒子数组letparticles=[];letanimationId=null;letisAnimating=false;letcurrentStep=0;lettotalSteps=1000;letscale=1;//缩放比例//更新参数functionupdateParams(){constheight=parseInt(document.getElementById('height').value);constwidth=parseInt(document.getElementById('width').value);constminRadius=parseInt(document.getElementById('minRadius').value);constmaxRadius=parseInt(document.getElementById('maxRadius').value);constporosity=parseFloat(document.getElementById('porosity').value);constcompression=parseFloat(document.getElementById('compression').value);//计算默认值constpaddingDefault=Math.floor(height/50);constforceDistanceDefault=Math.floor(height/10);//获取调整值constpaddingAdjust=parseInt(document.getElementById('paddingAdjust').value)||0;constforceDistanceAdjust=parseInt(document.getElementById('forceDistanceAdjust').value)||0;//计算最终值params.padding=paddingDefault+paddingAdjust;params.forceDistance=forceDistanceDefault+forceDistanceAdjust;//确保值在合理范围内params.padding=Math.max(5,Math.min(50,params.padding));params.forceDistance=Math.max(10,Math.min(200,params.forceDistance));params.height=height;params.width=width;params.minRadius=minRadius;params.maxRadius=maxRadius;params.porosity=porosity;params.compression=compression;params.springConstant=parseFloat(document.getElementById('springConstant').value);//计算扩展后的宽度params.expandedWidth=params.width*(1+params.compression);params.targetWidth=params.width;//计算缩放比例calculateScale();}//计算缩放比例functioncalculateScale(){constcontentWidth=params.expandedWidth;constcontentHeight=params.height;constcanvasWidth=canvas.width;constcanvasHeight=canvas.height;constscaleX=canvasWidth/contentWidth;constscaleY=canvasHeight/contentHeight;scale=Math.min(scaleX,scaleY);}//更新状态显示functionupdateStatus(){conststatusText=isAnimating?'正在模拟...':'准备就绪';constparticleCount=particles.length;constcurrentPorosity=calculatePorosity();statusElement.innerHTML=`<p>状态:${statusText}</p><p>颗粒数量:${particleCount}</p><p>当前孔隙率:${currentPorosity.toFixed(2)}</p><p>边界保护层:${params.padding}</p><p>力作用范围:${params.forceDistance}</p>`;}//计算当前孔隙率functioncalculatePorosity(){if(particles.length===0)return0;constcurrentWidth=params.expandedWidth-(params.expandedWidth-params.targetWidth)*(currentStep/totalSteps);consttotalArea=currentWidth*params.height;letfilledArea=0;particles.forEach(particle=>{filledArea+=Math.PI*particle.radius*particle.radius;});return1-filledArea/totalArea;}//生成初始粒子配置functiongenerateInitialParticles(){updateParams();particles=[];//计算需要的粒子数量consttargetPorosity=params.porosity/(1-params.compression);constmaxParticles=Math.floor((params.expandedWidth*params.height*(1-targetPorosity))/(Math.PI*Math.pow(params.minRadius,2)));//使用随机填充算法letattempts=0;constmaxAttempts=10000;while(particles.length<maxParticles&&attempts<maxAttempts){//随机生成粒子半径constradius=params.minRadius+Math.random()*(params.maxRadius-params.minRadius);//随机生成位置constx=params.padding+radius+Math.random()*(params.expandedWidth-2*(params.padding+radius));consty=params.padding+radius+Math.random()*(params.height-2*(params.padding+radius));//检查是否与现有粒子重叠letoverlap=false;for(constparticleofparticles){constdx=x-particle.x;constdy=y-particle.y;constdistance=Math.sqrt(dx*dx+dy*dy);if(distance<radius+particle.radius){overlap=true;break;}}if(!overlap){particles.push({x,y,radius,vx:0,vy:0});}attempts++;}updateStatus();drawParticles();}//绘制粒子functiondrawParticles(){ctx.clearRect(0,0,canvas.width,canvas.height);//计算当前宽度constcurrentWidth=params.expandedWidth-(params.expandedWidth-params.targetWidth)*(currentStep/totalSteps);constleftBoundary=params.padding+(params.expandedWidth-currentWidth)/2;constrightBoundary=leftBoundary+currentWidth-2*params.padding;//保存当前状态ctx.save();//设置缩放ctx.translate(canvas.width/2,canvas.height/2);ctx.scale(scale,scale);ctx.translate(-params.expandedWidth/2,-params.height/2);//绘制矩形边界ctx.strokeStyle='#333';ctx.lineWidth=2/scale;//调整线宽以适应缩放ctx.strokeRect(leftBoundary,params.padding,currentWidth-2*params.padding,params.height-2*params.padding);//绘制粒子particles.forEach(particle=>{ctx.beginPath();ctx.arc(particle.x,particle.y,particle.radius,0,Math.PI*2);consthue=Math.floor(Math.random()*360);ctx.fillStyle=`hsl(${hue},70%,60%)`;ctx.fill();ctx.strokeStyle='#333';ctx.lineWidth=1/scale;//调整线宽以适应缩放ctx.stroke();});//恢复状态ctx.restore();}//模拟压缩过程functionsimulateCompression(){if(isAnimating)return;isAnimating=true;currentStep=0;functionanimate(){if(currentStep>=totalSteps){isAnimating=false;updateStatus();return;}currentStep++;//更新粒子位置updateParticles();//绘制粒子drawParticles();animationId=requestAnimationFrame(animate);}animate();}//更新粒子位置和处理碰撞functionupdateParticles(){//计算当前宽度constcurrentWidth=params.expandedWidth-(params.expandedWidth-params.targetWidth)*(currentStep/totalSteps);constleftBoundary=params.padding+(params.expandedWidth-currentWidth)/2;constrightBoundary=leftBoundary+currentWidth-2*params.padding;//重置粒子速度for(constparticleofparticles){particle.vx=0;particle.vy=0;}//处理粒子之间的力for(leti=0;i<particles.length;i++){for(letj=i+1;j<particles.length;j++){applyDistanceForce(particles[i],particles[j]);}}//处理粒子与边界的碰撞for(constparticleofparticles){handleBoundaryCollision(particle,leftBoundary,rightBoundary);}//应用速度和位置更新for(constparticleofparticles){//添加一些阻尼效果particle.vx*=0.99;particle.vy*=0.99;//更新位置particle.x+=particle.vx;particle.y+=particle.vy;}}//应用基于距离的力functionapplyDistanceForce(p1,p2){constdx=p2.x-p1.x;constdy=p2.y-p1.y;constdistance=Math.sqrt(dx*dx+dy*dy);constminDistance=p1.radius+p2.radius;//当距离小于力作用范围时施加力if(distance<params.forceDistance){//计算力的大小(基于距离的力)letforceMagnitude=0;if(distance<minDistance){//接触时施加较大的排斥力forceMagnitude=params.springConstant*(minDistance-distance)*2;}else{//未接触时施加较小的吸引力forceMagnitude=params.springConstant*(params.forceDistance-distance)/params.forceDistance;}//计算力的方向constnx=dx/distance;constny=dy/distance;//应用力到两个粒子p1.vx-=forceMagnitude*nx;p1.vy-=forceMagnitude*ny;p2.vx+=forceMagnitude*nx;p2.vy+=forceMagnitude*ny;}}//处理粒子与边界的碰撞functionhandleBoundaryCollision(particle,leftBoundary,rightBoundary){//左边界if(particle.x-particle.radius<leftBoundary){particle.x=leftBoundary+particle.radius;particle.vx*=-0.5;//简化的弹性碰撞}//右边界if(particle.x+particle.radius>rightBoundary){particle.x=rightBoundary-particle.radius;particle.vx*=-0.5;}//上边界if(particle.y-particle.radius<params.padding){particle.y=params.padding+particle.radius;particle.vy*=-0.5;}//下边界if(particle.y+particle.radius>params.height-params.padding){particle.y=params.height-params.padding-particle.radius;particle.vy*=-0.5;}}//保存数据为CSV文件functionsaveData(){if(particles.length===0)return;//计算当前宽度constcurrentWidth=params.expandedWidth-(params.expandedWidth-params.targetWidth)*(currentStep/totalSteps);constleftBoundary=params.padding+(params.expandedWidth-currentWidth)/2;//创建CSV内容letcsvContent="ID,X,Y,Radius\n";particles.forEach((particle,index)=>{//以压缩后的左边界与下边界交点为原点constadjustedX=particle.x-leftBoundary;constadjustedY=particle.y-params.padding;csvContent+=`${index+1},${adjustedX},${adjustedY},${particle.radius}\n`;});//创建下载链接constblob=newBlob([csvContent],{type:'text/csv;charset=utf-8;'});consturl=URL.createObjectURL(blob);constlink=document.createElement('a');link.setAttribute('href',url);link.setAttribute('download','particle_data.csv');link.style.visibility='hidden';document.body.appendChild(link);link.click();document.body.removeChild(link);}//事件监听器generateBtn.addEventListener('click',generateInitialParticles);animateBtn.addEventListener('click',simulateCompression);saveBtn.addEventListener('click',saveData);resetBtn.addEventListener('click',()=>{if(animationId){cancelAnimationFrame(animationId);animationId=null;}particles=[];isAnimating=false;updateStatus();drawParticles();});//初始化updateParams();drawParticles();</script></body></html>来源:锂想生活