import { getEtaTable28 } from '../nbr-tables/table-28'; import { linearInterp1D } from '../log-interp'; export interface PipeDef { id: string; diameter: number; // diâmetro ou altura do equipamento em metros elevationOffset: number; // posição Y relativa à base do reticulado (0 a h) } export interface PiperackInput { width: number; // b: largura do pórtico ortogonal ao vento (m) height: number; // h: altura do pórtico/seção transversal (m) elevation: number; // z: elevação média em relação ao solo (m) spacing: number; // e: distância entre pórticos subsequentes (m) numFrames: number; // n: número de pórticos paralelos na direção do vento phiStruct: number; // φ_str: índice de solidez apenas da estrutura metálica pipes: PipeDef[]; // Lista de tubulações correndo longitudinalmente q: number; // q: Pressão dinâmica na elevação z (kN/m²) } export interface PiperackResult { phiTotal: number; caFrontal: number; eta: number; linearLoadFront: number; // kN/m (carga no pórtico 1) linearLoadBack: number; // kN/m (carga nos pórticos 2..n) globalForce: number; // kN (força total na estrutura) effectiveElevation: number; // z_eff: Altura efetiva de aplicação da força global (m) } /** Tabela de Ca genérica para reticulados planos (faces planas) baseada na solidez φ (Tabela 26) */ const PHI_ARRAY = [0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6]; const CA_FLAT_ARRAY = [3.6, 3.0, 2.4, 2.0, 1.8, 1.7, 1.6]; export function calculatePiperack(input: PiperackInput): PiperackResult { const { width, height, elevation, spacing, numFrames, phiStruct, pipes, q } = input; // 1. Calcular o Índice de Solidez Total (φ) e Centro de Pressão Efetivo let sumPhiZ = phiStruct * elevation; // Momento de área estática estrutural const phiPipes = pipes.reduce((sum, pipe) => { const phiP = pipe.diameter / height; const pipeZ = (elevation - height / 2) + pipe.elevationOffset; sumPhiZ += phiP * pipeZ; return sum + phiP; }, 0); const rawPhi = phiStruct + phiPipes; const phiTotal = Math.min(Math.max(rawPhi, 0.05), 1.0); // Z efetivo é a média ponderada pelas áreas de bloqueio (se rawPhi=0, usa elevation) const effectiveElevation = rawPhi > 0 ? sumPhiZ / rawPhi : elevation; // 2. Coeficiente de Arrasto Frontal (Ca) para o primeiro pórtico let caFrontal = 1.6; if (phiTotal <= 0.6) { caFrontal = linearInterp1D(PHI_ARRAY, CA_FLAT_ARRAY, phiTotal); } else { caFrontal = 1.6 - (phiTotal - 0.6) * 1.0; } // 3. Fator de proteção (η) para pórticos a sotavento const eh = spacing / height; const eta = getEtaTable28(phiTotal, eh); // 4. Forças Lineares (kN/m) const effectiveAreaPerMeter = phiTotal * height; const linearLoadFront = q * effectiveAreaPerMeter * caFrontal; const linearLoadBack = linearLoadFront * eta; // 5. Força Global (kN) const totalLinearLoad = linearLoadFront + (numFrames > 1 ? linearLoadBack * (numFrames - 1) : 0); const globalForce = totalLinearLoad * width; return { phiTotal, caFrontal, eta, linearLoadFront, linearLoadBack, globalForce, effectiveElevation }; }