import {clamp} from './units.js?v=45'; export class ResourceField{ constructor({id,role,cellCount,energyDensityKJPerKg,representation='field'}){this.id=id;this.role=role;this.energyDensityKJPerKg=energyDensityKJPerKg;this.representation=representation;this.biomass=new Float32Array(cellCount)} consume(index,amountKg,cellAreaM2){const available=this.biomass[index]*cellAreaM2,taken=Math.min(Math.max(0,amountKg),available);this.biomass[index]=Math.max(0,this.biomass[index]-taken/cellAreaM2);return taken} } export const phytoplanktonMuMax = temperatureC => 0.81 * Math.exp(0.0631 * temperatureC); export function producerCapacity(profile,{moisture=1,shade=0,blocked=false}={}){ if(blocked)return 0; if(profile.type==='terrestrial')return profile.producer.carryingCapacityKgPerM2 * clamp(0.35 + 0.65*moisture,0,1) * (1 - 0.18*clamp(shade,0,1)); return profile.producer.carryingCapacityKgPerM2; } export function producerGrowthPerDay(profile,temperatureC,{moisture=1,light,nutrientN,nutrientP}={}){ if(profile.type==='terrestrial'){ const fT=Math.exp(-0.5*((temperatureC-20)/13)**2),fW=clamp(moisture,0,1),fL=clamp(light ?? profile.environment.light,0,1); return profile.producer.rMaxPerDay * fT * fW * fL; } const fI=clamp(light ?? profile.environment.light,0,1),fN=clamp(nutrientN ?? profile.environment.nutrientN,0,1),fP=clamp(nutrientP ?? profile.environment.nutrientP,0,1); return phytoplanktonMuMax(temperatureC) * Math.min(fN,fP) * fI; } export function updateProducerBiomass(biomass,capacity,growthPerDay,consumedKgPerM2,dtDays){ if(capacity<=0)return 0;const growth=growthPerDay*biomass*(1-biomass/capacity);return clamp(biomass + growth*dtDays - Math.max(0,consumedKgPerM2),0,capacity*1.05); } export function updateZooplanktonCohort(producerKgPerM2,zooplanktonKgPerM2,dtDays=1){ const z=Math.max(0,zooplanktonKgPerM2),p=Math.max(0,producerKgPerM2),ingestion=Math.min(p,.9*z*p/(.035+p))*dtDays,assimilated=ingestion*.45,mortality=.10*z*dtDays; return {producerConsumedKgPerM2:ingestion,nextZooplanktonKgPerM2:Math.max(0,z+assimilated-mortality),productionKgPerM2:Math.max(0,assimilated-mortality)}; }