Desenvolva um programa em Python que permita calcular a altura do fluido h(t) em função do volume do tanque elíptico. O programa deve:
  1. Definir os parâmetros geométricos do tanque ( D_{\text {max }}, D_{\text {min }}, L );
  2. Calcular a área molhada A(h(t)) da elipse para diferentes valores de h(t);
  3. Determinar o volume acumulado V=A(h(t)) \cdot L;
  4. Gerar um gráfico mostrando a variação de V em função de h(t);
  5. Permitir a entrada de novos valores de h(t) pelo usuário e retornar o volume correspondente.

Passo 1

O que o exercício pede (resumido e claro):
  • Construir um programa em Python que permita calcular a altura do fluido h(t) em função do volume do tanque elíptico — mais precisamente: dado um h(t) calcular o volume V.
  • O programa deve:
    1. Definir os parâmetros geométricos do tanque: D_{\text{max}} (diâmetro vertical), D_{\text{min}} (diâmetro horizontal) e L (comprimento do tanque).
    2. Calcular a área molhada da seção elíptica A(h) para diferentes valores de h.
    3. Determinar o volume acumulado V(h)=A(h)\cdot L.
    4. Gerar um gráfico mostrando a variação de V em função de h.
    5. Permitir a entrada de novos valores de h pelo usuário e retornar o volume correspondente.
Informações fornecidas e convenções que vou usar sem perguntar:
  • O tanque tem seção transversal elíptica com diâmetros D_{\text{max}} (vertical) e D_{\text{min}} (horizontal).
  • Vou medir h a partir do ponto mais baixo da elipse (ou seja, h=0 → vazio; h=D_{\text{max}} → cheio).
  • O volume total para um determinado h é V(h)=A(h)\cdot L.

Passo 2

Entendendo a geometria da elipse — derivação da área molhada A(h) passo a passo (a parte matemática):
  • Definições das grandezas geométricas: a = \frac{D_{\text{max}}}{2}\quad\text{(semi-eixo vertical)}
b = \frac{D_{\text{min}}}{2}\quad\text{(semi-eixo horizontal)}
  • Colocamos a elipse centrada na origem com equação \frac{x^{2}}{b^{2}}+\frac{y^{2}}{a^{2}}=1.O fundo da elipse corresponde a y=-a e o topo a y=+a. Um nível de líquido h (medido a partir do fundo) corresponde à coordenada vertical y_{h} = -a + h.O domínio válido é 0 \le h \le 2a.
  • A largura da elipse em uma altura y é 2x(y) com x(y)=b\sqrt{1-\frac{y^{2}}{a^{2}}}.Então a área do segmento da base até y_{h} é A(h)=\int_{y=-a}^{y=y_{h}} 2x(y)\,dy =2b\int_{-a}^{y_{h}} \sqrt{1-\frac{y^{2}}{a^{2}}}\,dy.
  • Para calcular essa integral, fazemos a substituição y=a\sin\theta. Então: y=-a \Rightarrow \theta=-\frac{\pi}{2},\qquad y=y_{h}\Rightarrow \theta=\theta_{h}=\arcsin\!\left(\frac{y_{h}}{a}\right).Com dy=a\cos\theta\,d\theta e \sqrt{1-\frac{y^{2}}{a^{2}}}=\cos\theta, obtemos A(h)=2b\int_{-\pi/2}^{\theta_{h}} a\cos^{2}\theta\,d\theta =2ab\int_{-\pi/2}^{\theta_{h}} \cos^{2}\theta\,d\theta.
  • Usando \cos^{2}\theta=\tfrac{1+\cos(2\theta)}{2} e integrando, A(h)=ab\left[\theta+\tfrac{\sin(2\theta)}{2}\right]_{-\pi/2}^{\theta_{h}} =ab\left(\theta_{h}+\tfrac{\sin(2\theta_{h})}{2}+\tfrac{\pi}{2}\right).
  • Substituindo \theta_{h}=\arcsin\!\big(\tfrac{y_{h}}{a}\big)=\arcsin\!\big(-1+\tfrac{h}{a}\big), obtemos a fórmula final prática: A(h)=ab\left(\arcsin\!\left(\frac{-a+h}{a}\right)+\frac{\sin\!\big(2\arcsin\!\left(\frac{-a+h}{a}\right)\big)}{2}+\frac{\pi}{2}\right).Essa expressão verifica os casos extremos:
    • h=0\Rightarrow A(0)=0.
    • h=2a\Rightarrow A(2a)=\pi ab (área total da elipse).
  • O volume associado é simplesmente V(h)=A(h)\cdot L.

Passo 3

Como implementar isso numericamente de forma estável e conveniente em Python (boas práticas rápidas):
  • Observações numéricas:
    • Ao calcular \arcsin é importante garantir que seu argumento esteja em [-1,1]. Por causa de erros numéricos, vamos usar um truncamento com \text{clip}.
    • A expressão \sin(2\theta_h) pode ser calculada com \sin(2\theta_h) diretamente.
  • Algoritmo para a função que calcula A(h):
    1. Recebe h (pode ser escalar ou array), D_{\text{max}} e D_{\text{min}}.
    2. Calcula a e b.
    3. Calcula y_h = -a + h.
    4. Calcula argumento para arcsin: u = y_h / a e aplica \text{clip}(u,-1,1).
    5. \theta_h = \arcsin(u).
    6. A = a b \left(\theta_h + \tfrac{\sin(2\theta_h)}{2} + \tfrac{\pi}{2}\right).
  • Em seguida V(h)=A(h)\cdot L.
  • Vamos escrever funções vetorizadas (usando NumPy) para permitir plot e entrada múltipla de h.

Passo 4

Como gerar o gráfico V em função de h:
  • Gera um vetor de alturas h uniformemente espaçadas em [0,D_{\text{max}}], por exemplo com 300 pontos.
  • Calcula V(h) para cada ponto (vetorizado).
  • Usa matplotlib para plotar V no eixo vertical e h no eixo horizontal. Coloca título, rótulos e grid.
  • Opcionalmente plota uma linha indicando o volume total quando h=D_{\text{max}}.

Passo 5

Interação com o usuário para entrada de novos valores de h:
  • Permitir que o usuário digite um único h ou vários separados por vírgula.
  • Para cada h verificar se pertence ao intervalo [0,D_{\text{max}}]. Se inválido, avisar e pular.
  • Calcular e imprimir A(h) e V(h) com formatação amigável (por exemplo, 3 casas decimais).
  • Repetir até o usuário digitar uma palavra de saída (por exemplo “sair” ou pressionar Enter sem valor).

Passo 6

Código Python completo pronto para uso (explicação curta dos blocos no código):
  • O código a seguir implementa:
    • funções: compute_area(h, Dmax, Dmin), compute_volume(h, Dmax, Dmin, L);
    • rotina de plotagem plot_V_vs_h(Dmax, Dmin, L);
    • loop interativo ask_user_loop(Dmax, Dmin, L);
    • um bloco principal com exemplo de parâmetros iniciais que o usuário pode modificar.

Resposta

#!/usr/bin/env python3
"""
Programa para cálculo da área molhada A(h) e do volume V(h) de um tanque com
seção transversal elíptica. Também gera gráfico V x h e permite entrada
interativa de valores de h.

Como usar:
- Execute o script.
- No bloco principal você pode ajustar D_max, D_min e L.
- O script plota V(h) e depois entra em modo interativo para consultar volumes.
"""

import numpy as np
import matplotlib.pyplot as plt

def compute_area(h, D_max, D_min):
    """
    Calcula a área molhada A(h) da seção elíptica até a altura h medida a partir do fundo.
    Parâmetros:
      h      : escalar ou array de alturas (mesma unidade de D_max)
      D_max  : diâmetro vertical da elipse (altura total)
      D_min  : diâmetro horizontal da elipse (largura)
    Retorna:
      A(h)   : área(s) correspondente(s) (mesma unidade^2)
    Observações:
      - h deve estar no intervalo [0, D_max]. Se for array, cada elemento deve obedecer.
    """
    a = D_max / 2.0   # semi-eixo vertical
    b = D_min / 2.0   # semi-eixo horizontal

    # Converte h em array numpy para suportar vetorização
    h_arr = np.asarray(h, dtype=float)

    # Coordenada y_h correspondente (origem no centro da elipse): y_h = -a + h
    y_h = -a + h_arr

    # argumento para arcsin: u = y_h / a
    # clip para evitar valores ligeiramente fora de [-1,1] por erros numéricos
    u = np.clip(y_h / a, -1.0, 1.0)

    theta_h = np.arcsin(u)  # em radianos

    # A(h) = a*b*(theta_h + sin(2*theta_h)/2 + pi/2)
    A = a * b * (theta_h + 0.5 * np.sin(2.0 * theta_h) + 0.5 * np.pi)

    # Para valores de h fora do intervalo [0, 2a] (ou seja [0, D_max]) colocamos 0 ou área total
    # Isso torna a função tolerante a entradas fora do intervalo.
    full_area = np.pi * a * b
    if np.isscalar(h):
        if h < 0:
            return 0.0
        if h > D_max:
            return full_area
    else:
        # vetor: ajustar extremos
        A = np.where(h_arr <= 0.0, 0.0, A)
        A = np.where(h_arr >= D_max, full_area, A)

    return A

def compute_volume(h, D_max, D_min, L):
    """
    Volume V(h) = A(h) * L
    """
    A = compute_area(h, D_max, D_min)
    return A * L

def plot_V_vs_h(D_max, D_min, L, npoints=300, show=True, savepath=None):
    """
    Gera gráfico de V(h) para h variando de 0 a D_max.
    """
    h_vals = np.linspace(0.0, D_max, npoints)
    V_vals = compute_volume(h_vals, D_max, D_min, L)

    plt.figure(figsize=(8,5))
    plt.plot(h_vals, V_vals, '-b', lw=2, label='V(h) = A(h)·L')
    plt.xlabel('Altura do fluido h (mesma unidade de D_max)')
    plt.ylabel('Volume V(h) (unidade^3)')
    plt.title('Variação do volume V em função da altura h')
    plt.grid(True)
    plt.legend()
    if savepath:
        plt.savefig(savepath, dpi=150)
    if show:
        plt.show()

def ask_user_loop(D_max, D_min, L):
    """
    Loop interativo que permite ao usuário entrar com valores de h e obter o volume.
    O usuário pode digitar:
      - um número (ex: 0.5)
      - vários números separados por vírgula (ex: 0.2, 1.0, 2.3)
      - 'sair' ou linha vazia para encerrar
    """
    prompt = (
        "\nDigite um valor de h (ou vários separados por vírgula) para calcular V(h),\n"
        "ou digite 'sair' para encerrar.\n"
        f"Intervalo válido: 0 <= h <= {D_max}\n"
        "Entrada: "
    )
    while True:
        s = input(prompt).strip()
        if s == "" or s.lower() == "sair":
            print("Encerrando. Até a próxima!")
            break
        # tenta separar por vírgula
        parts = [p.strip() for p in s.split(',') if p.strip() != ""]
        hs = []
        ok = True
        for p in parts:
            try:
                val = float(p.replace(',', '.'))  # aceita vírgula decimal também
                hs.append(val)
            except ValueError:
                print(f"Entrada inválida: '{p}'. Tente novamente.")
                ok = False
                break
        if not ok:
            continue

        hs_arr = np.array(hs, dtype=float)
        # valida intervalo
        for i, hh in enumerate(hs_arr):
            if hh < 0.0 or hh > D_max:
                print(f"  Atenção: h={hh} está fora do intervalo [0, {D_max}]. Ignorando esse valor.")
        # calcula volumes (a função trata valores fora do intervalo também, mas avisamos)
        Vs = compute_volume(hs_arr, D_max, D_min, L)
        for hh, vv in zip(hs_arr, Vs):
            # Impressão com 3 casas decimais
            print(f"  h = {hh:.6g} -> V = {vv:.6g} (unidade^3)")

def main():
    # Exemplo de parâmetros iniciais (você pode alterar aqui)
    D_max = 2.0   # exemplo: 2 metros (altura)
    D_min = 1.0   # exemplo: 1 metro (largura)
    L     = 5.0   # comprimento do tanque em metros

    print("Parâmetros do tanque:")
    print(f"  D_max = {D_max}")
    print(f"  D_min = {D_min}")
    print(f"  L     = {L}")

    # Plot V(h)
    plot_V_vs_h(D_max, D_min, L, npoints=400)

    # Modo interativo
    ask_user_loop(D_max, D_min, L)

if __name__ == "__main__":
    main()

Exercícios relacionados