International Essays |
Quanto tempo leva para cozinhar um ovo? Modelagem FEM com a Wolfram Language
Quanto tempo leva para cozinhar um ovo? Modelagem FEM com a Wolfram Language
15 de setembro de 2025
Ricardo López, Physics Applications Developer Intern, Algorithms R&D; Gay Wilson, Food Data Curator, Wolfram|Alpha Scientific Content; Oliver Ruebenkoenig, Senior Kernel Developer, Algorithms R&D
É hora de responder à pergunta que está na cabeça de qualquer amante de café da manhã: “Por quanto tempo devo cozinhar um ovo?” Embora pareça simples colocar um ovo em água fervente e esperar, seria um erro dizer que um ovo totalmente cozido é a única maneira de desfrutar de um delicioso impulso de proteína. Podemos usar o método dos elementos finitos (FEM) para simular as condições de um ovo na água e encontrar a temperatura e o tempo ideais para o ovo perfeito, avaliando as mudanças de temperatura dentro do próprio ovo. Assim, podemos prever quanto tempo leva para atingir diferentes consistências, como uma gema mole ou uma gema firme e totalmente cozida.
A modelagem de sistemas físicos complexos geralmente começa dividindo-os em partes gerenciáveis. É exatamente isso que o FEM faz: ele divide uma estrutura complicada em elementos menores e mais simples; resolve as equações que regem o sistema localmente; e depois reúne os resultados para capturar o comportamento do sistema como um todo.
Essa abordagem possibilita simular e analisar cenários do mundo real sem o custo e o esforço de criar protótipos físicos. Aqui, apresentaremos o fluxo de trabalho da análise por elementos finitos em Wolfram Language e passaremos por um exemplo simples que aborda os conceitos básicos e destaca questões comuns que podem surgir durante o processo.
Nosso objetivo é fornecer uma compreensão geral de como resolver numericamente equações diferenciais parciais (EDPs) usando o FEM, juntamente com um recurso prático que pode ser utilizado para construir seus próprios modelos.
Por que usar elementos finitos?
Por que usar elementos finitos?
Muitas EDPs (incluindo equações clássicas como a Poisson ou as equações de Schrödinger) nem sempre possuem uma solução analítica, especialmente se a região onde tentamos resolver a equação for um pouco complicada. O FEM é uma técnica valiosa para resolver EDPs numericamente por pelo menos dois motivos: primeiro, é possível resolver EDPs em regiões de formato arbitrário. Segundo, é possível resolver muitos tipos de equações diferenciais, desde a equação de Laplace até as equações de Navier–Stokes.
Ferramentas Necessárias para Análise por Elementos Finitos
Ferramentas Necessárias para Análise por Elementos Finitos
◼
Uma região que é subdividida em uma malha. Essa malha consiste em várias pequenas sub-regiões simples chamadas elementos. A ideia principal do FEM é resolver uma versão simplificada da EDP dentro de cada elemento e, em seguida, combinar essas soluções locais em uma solução global que aproxime o comportamento da EDP original em toda a região.
◼
A PDE específica que queremos resolver.
◼
Condições de contorno, que conectam a PDE ao mundo fora da região onde a solução está sendo calculada.
Na Wolfram Language, o FEM é implementado por meio das funções , e , e utilizaremos NDSolveValue no nosso cenário do ovo fervendo.
Versão 1: Iniciar um Fluxo de Trabalho
Versão 1: Iniciar um Fluxo de Trabalho
Vamos construir nosso modelo passo a passo, passando por várias versões e aumentando a complexidade do modelo de forma incremental. Começaremos com um modelo simples, tendo em mente os tamanhos dos objetos e as unidades.
O primeiro passo é definir a geometria ou a região da estrutura. Como um ovo possui simetria axial, assumiremos que analisar uma fatia do ovo é suficiente para descrever seu comportamento. Para o FEM, precisamos subdividir a região em uma malha, e como uma malha bidimensional não necessita de tantos elementos para aproximar a geometria quanto uma malha tridimensional, nosso cálculo levará menos tempo. Esta é uma razão importante para usar um modelo axisimétrico.
Um ovo médio pode ter cerca de 5 cm de diâmetro e 2,5 cm de raio. Como é prática recomendada usar unidades do SI para os parâmetros do modelo, definiremos o raio do ovo como 0,025 m. Neste momento, estamos propositalmente ignorando qualquer diferença entre o material da gema e da clara. Nosso objetivo é tornar esta versão inicial do modelo o mais simples possível.
Carregue o pacote de Elementos Finitos:
In[]:=
Needs["NDSolve`FEM`"]
Também definiremos como 0, que limita o número de resultados anteriores armazenados na sessão a zero, economizando memória computacional a um custo mínimo.
Defina $HistoryLength para 0:
In[]:=
$HistoryLength=0;
Crie uma geometria simples de um ovo:
In[]:=
radius=0.025;Ω=RegionUnion[Circle[{0,0},radius,{-π/2,π/2}],Line[{{0,radius},{0,-radius}}]]
Out[]=
Além disso, utilizamos ToElementMesh para gerar uma malha de elementos finitos padrão a partir da geometria que acabamos de criar.
Gere a malha de elementos:
In[]:=
mesh=ToElementMesh[Ω]
Out[]=
ElementMesh[{{0.,0.025},{-0.025,0.025}},{TriangleElement[<492>]}]
Visualize a malha de elementos finitos:
In[]:=
mesh["Wireframe"]
Out[]=
Para modelar EDPs em Wolfram Language, usamos o que são chamados de componentes de EDP, que são blocos de construção que nos ajudam a especificar as EDPs. São funções que recebem variáveis e parâmetros e retornam um operador de EDP que pode então ser usado com NDSolveValue. Você pode acessar a lista de todos os componentes de EDP para qualquer campo específico. Para estudar a evolução da temperatura dentro do ovo, usaremos para modelar a transferência de calor ao longo do tempo.
A solução que estamos procurando, a variável dependente, é a temperatura (kelvin). Para nossa simetria cilíndrica, temos duas variáveis independentes espaciais: r é a coordenada radial (distância do eixo central) e z é a coordenada axial (distância ao longo do eixo do cilindro). Ambas são expressas em metros. Como o cozimento de um ovo depende do tempo, também precisaremos da variável tempo t (segundos).
T
Defina as variáveis dependentes e independentes do modelo:
In[]:=
vars={T[t,r,z],t,{r,z}};
Também precisamos dos parâmetros. Para nossa primeira versão simplificada, vamos especificar apenas a simetria da região como axialmente simétrica, e isso nos fornecerá os termos corretos para a fatia do ovo na qual estamos focando. HeatTransferPDEComponent preencherá o restante dos parâmetros necessários com valores padrão, e isso é suficiente por enquanto.
Defina os parâmetros:
In[]:=
pars=<|"RegionSymmetry"->"Axisymmetric"|>;
Em seguida, defina o operador de EDP. Aqui, é o operador de EDP — é simplesmente o lado esquerdo da equação do calor. Portanto, quando escrevemos , estamos na verdade apenas escrevendo a própria equação do calor.
op
op0
Configure o operador EDP:
In[]:=
op=HeatTransferPDEComponent[vars,pars]
Out[]=
-,0.T[t,r,z]+·{{-1,0},{0,-1}}.T[t,r,z]+[t,r,z]
1
r
∇
{r,z}
∇
{r,z}
∇
{r,z}
(1,0,0)
T
In[]:=
op==0
Out[]=
-,0.T[t,r,z]+·{{-1,0},{0,-1}}.T[t,r,z]+[t,r,z]0
1
r
∇
{r,z}
∇
{r,z}
∇
{r,z}
(1,0,0)
T
Condições de Contorno
Condições de Contorno
Condições iniciais e de contorno são partes importantes da modelagem de EDPs porque contêm informações sobre a física subjacente do processo em questão. As condições de contorno especificam o comportamento da solução nos limites. Neste cenário, uma condição de contorno importante é o exterior do ovo, que está sujeito à temperatura da água fervente ao redor. A condição inicial é a temperatura inicial do ovo, se o ovo foi refrigerado ou armazenado em temperatura ambiente.
Assumindo que o ovo está à temperatura ambiente, usaremos 20°C como nossa condição inicial no tempo 0 e, em seguida, converteremos para a unidade base do SI, o kelvin.
Defina a temperatura inicial em kelvins:
Defina uma condição inicial para a temperatura dentro do ovo:
É importante lembrar que as condições de contorno e as condições iniciais devem ser consistentes. Pode-se ficar tentado a simplesmente definir uma temperatura de 100 °C na parte externa da região, representando o contato com a água fervente. Embora isso não esteja totalmente errado, há um problema. Pela nossa condição inicial, todo o domínio tem uma temperatura inicial de 20 °C, até mesmo no limite externo. Portanto, definir o limite externo para 100 °C contradiz isso.
Para evitar isso em nosso cenário, usamos uma função de passo suave que começa na temperatura inicial e rapidamente atinge a temperatura de ebulição de 100°C. Isso modela efetivamente o ato de colocar o ovo na água fervente, que é um processo por si só.
Especificamente, definimos a condição de contorno usando uma função por partes que é igual a 1 para tempos maiores que um décimo (1/10) de segundo. Para tempos menores, ela aumenta gradualmente, seguindo uma função cosseno. Ao plotar a função, esse comportamento fica mais claro. Isso modela a temperatura de contorno aumentando rapidamente — mas de forma suave — nos primeiros 1/10 de segundo após o ovo ser imerso em água fervente.
Especifique a temperatura de fronteira em kelvins:
Especifique o comportamento temporal da condição de contorno:
Visualize o comportamento temporal da condição de contorno:
Mas faremos algo diferente que será útil em versões subsequentes deste modelo.
Visualize o marcador de elemento pontual:
Nossa visualização de malha exibe os elementos de ponto e os marcadores de elemento (consulte o tutorial Element Mesh Visualization para mais informações). Vamos aproveitar isso para definir a condição de contorno.
Uma vantagem de usar a função HeatTemperatureCondition é que ela levará em consideração os parâmetros que definimos.
Especifique a condição de contorno em kelvins:
Especifique a condição de simetria:
Observe que isso resulta em um valor nulo de Neumann. Se precisar relembrar sobre valores de Neumann, confira essas fontes na documentação:
Um valor de Neumann zero, em termos simples, indica que a derivada da temperatura, tomada na direção normal ao eixo de simetria, é zero. Além disso, um valor de Neumann zero é o padrão se nenhum for especificado. Portanto, iremos omitir isso nas próximas versões deste modelo. Mas é útil ter isso em mente.
Finalmente, definimos quanto tempo durará a simulação. Como esta é uma primeira versão simples e utilizamos os parâmetros padrão para nossa PDE, definimos um tempo de um segundo, que iremos atualizar posteriormente.
Defina o tempo de simulação:
Para obter nossa solução, usamos NDSolveValue.
Calcule a solução e armazene-a em uma variável:
Inspecione a solução:
Obtemos uma função interpoladora que representa nossa solução, a qual podemos posteriormente plotar para visualizar a solução.
Chamar "ValuesOnGrid" fornece os valores da função em cada coordenada da malha. Em seguida, podemos extrair os valores mínimo e máximo da solução.
Para facilitar a interpretação, vamos transformar as temperaturas para graus Celsius, mas os parâmetros utilizados no modelo ainda precisarão ser definidos em kelvin. Portanto, vamos definir um deslocamento para converter mais facilmente entre graus Celsius e kelvin.
Defina um deslocamento:
O gráfico parece mostrar que toda a região atinge uma temperatura de 100°C em apenas metade do tempo de simulação (0,5 segundo). Para confirmar isso, vamos criar uma animação da evolução da temperatura ao longo do tempo.
Para economizar tempo depois, vamos em frente e construir uma função auxiliar para plotagem.
Construa uma função auxiliar para criar gráficos de contorno da temperatura em vários instantes de tempo:
Criamos uma função da variável time, que nos fornece o gráfico para um determinado instante. Em seguida, podemos aplicar essa função a uma lista de instantes.
Defina uma versão de DensityPlot da função auxiliar:
Crie vários quadros de gráfico de contorno:
Rasterize os quadros para tornar o notebook mais leve (isso é opcional):
Anime os quadros:
A animação demonstra que toda a região começa na temperatura inicial e quase instantaneamente aquece até 100°C (a temperatura da água), o que não faz muito sentido. Mas não esperávamos que essa fosse nossa solução final. Por enquanto, sabemos que não há erros ou avisos em nossa simulação. Esta etapa tinha o objetivo de iniciar nosso fluxo de trabalho — e é isso que realmente importa neste estágio do modelo.
Versão 2: Um Exemplo do Que Pode Dar Errado
Versão 2: Um Exemplo do Que Pode Dar Errado
Agora que nosso fluxo de trabalho está estabelecido, começamos esta próxima versão definindo parâmetros mais realistas em vez daqueles que HeatTransferPDEComponent (a função usada para gerar a PDE) fornece por padrão.
A equação do calor inclui três grandezas físicas que dependem do tipo de material que estamos modelando: densidade, capacidade térmica e condutividade térmica:
Vamos usar estimativas dos valores médios tanto da clara quanto da gema do ovo para definir os parâmetros do material:
Inspecione os parâmetros:
Defina um tempo realista de término da simulação de 10 minutos:
Regenere as equações com os novos parâmetros:
Como fizemos antes, resolva a PDE:
Até agora, tudo bem!
Vamos verificar os valores mínimos e máximos na solução em graus Celsius:
Isto está claramente errado. Uma temperatura abaixo de zero aqui não faz sentido algum. Vamos plotar a solução no momento específico em que ela atinge essa temperatura abaixo de zero.
Encontre a posição do valor mínimo nos dados da solução:
Ao chamar "Coordinates" na solução e pegar a primeira parte, obtemos os passos de tempo realizados durante a solução:
Encontre o passo de tempo no qual o valor mínimo é armazenado:
Na nossa variável badPosition, que é {{18, 386}}, o primeiro número do par representa o índice para o instante em que ocorre nosso valor abaixo de zero. Podemos extrair o tempo problemático pegando a décima oitava posição nos passos de tempo:
Agora podemos visualizar a solução nesse instante exato.
Visualize a solução no passo de tempo com os valores extremos:
Aqui fica claro como, no início da simulação, há muitas oscilações próximas ao limite, e é por isso que estamos observando temperaturas extremas próximas de –2°C. O gráfico 3D exibe excessos e deficiências.
Aproxime o zoom do gráfico da solução e visualize a malha de elementos finitos subjacente:
Eu recomendo a revisão da documentação de ElementMeshProjection para aprender mais sobre como visualizar uma malha 2D em 3D.
Agora está claro que os subpicos estão ocorrendo a poucos elementos da borda. Mas o que poderia estar causando esses sobre- e subpicos?
Obtenha o comprimento mínimo da aresta da malha em\b metros:
A distância entre os elementos é de aproximadamente 1 mm, o que significa que os primeiros elementos próximos ao limite têm um comprimento de aresta de cerca de 1 mm. Por outro lado, considerando que nossa temperatura inicial é 20°C e a temperatura no limite é 100°C, a variação de temperatura entre o limite e o restante da região é de cerca de 80°C.
Tentar resolver essa mudança abrupta de cerca de 80°C na fronteira com elementos desse tamanho não é suficiente. Essa provavelmente é a razão pela qual estamos obtendo temperaturas muito abaixo da temperatura inicial, onde não há dissipadores de calor. Portanto, a malha precisa ser refinada.
Se refinarmos toda a malha, provavelmente isso resolverá o nosso problema, mas o refinamento não é necessário no centro do ovo. Refinar toda a malha agora vai deixar a simulação mais lenta, então é melhor refinar a malha apenas próximo à borda (a casca do ovo).
Crie uma função de distância assinada de toda a região do ovo:
Podemos visualizar a função de distância assinada e observar como ela diminui linearmente ao se aproximar da borda. Esse resultado faz sentido, pois a distância da casca até ela mesma é previsivelmente zero.
Visualize a função de refinamento sobre a geometria malhada:
Crie a função de refinamento de malha:
Em seguida, definimos a opção MeshRefinementFunction dentro de ToElementMesh para a nossa refinementFunction.
Redefina a malha:
Resolva a EDP e acompanhe o progresso:
Verifique a faixa de temperatura da solução recém-encontrada:
Ótimo! Agora obtemos um intervalo de temperatura que esperaríamos. Haverá, é claro, um pouco de erro numérico intrínseco ao método — ou seja, o intervalo não será exatamente {20, 100}. Mas isso é promissor.
Podemos prosseguir para criar nossa animação normalmente, chamando a função auxiliar que definimos com nossa nova solução, rasterizando os quadros e depois animando-os.
Crie os quadros para a solução:
Rasterize as quadros:
Animar os quadros:
Podemos ver que o problema de sobre-elevação e sub-elevação foi resolvido. Isso demonstra como é importante verificar se nossas soluções fazem sentido e como podemos modificar a malha conforme necessário.
Neste ponto, temos uma boa ideia de como a temperatura se distribui durante a fervura do ovo. Vamos calcular a temperatura no centro do ovo após seis minutos de cozimento.
O resultado é 41,6°C. Esse valor provavelmente não representa a temperatura real da gema de um ovo verdadeiro, pois atualmente estamos fazendo muitas suposições. No entanto, é uma boa referência por enquanto.
Nesta versão, utilizamos um modelo básico que desconsiderou a existência de duas regiões diferentes — a gema e a clara do ovo. Abordaremos isso na próxima versão.
Versão 3: Representar Múltiplas Regiões de Material
Versão 3: Representar Múltiplas Regiões de Material
Crie uma geometria com múltiplos materiais:
Aqui definimos marcadores de regiões materiais para diferenciar os parâmetros das duas regiões posteriormente. Isso tornará nosso código mais claro, como veremos.
Especifique marcadores de regiões de material:
Utilizamos a opção "RegionMarker" para distinguir as duas regiões, atribuindo um marcador diferente a cada sub-região. A opção é fornecida como uma lista de listas, em que cada lista interna contém um ponto dentro da sub-região e seu respectivo marcador de região.
Crie uma malha com marcadores de material:
Podemos visualizá-lo com cores diferentes, especificando "MeshElementStyle" nas opções de "Wireframe".
Visualize a malha com múltiplos materiais:
Visualize os marcadores de elementos pontuais:
Como alteramos a região, os marcadores de elemento para o contorno também foram modificados. Portanto, podemos redefinir a condição de contorno para os marcadores 2 e 5.
Lembre-se de que estes são marcadores de elementos para o limite. Eles são diferentes dos marcadores de região que definimos anteriormente. Não confunda os dois.
Regenere a condição de contorno:
Depois de visualizar os marcadores de elemento de ponto, redefinimos a malha especificando a função de refinamento da malha como antes.
Crie uma malha com marcadores de material e um refinamento de malha:
Visualize a malha refinada de múltiplos materiais:
Ótimo resultado! Mas antes de resolver o problema, vamos redefinir os parâmetros para cada material, usando estimativas dos valores médios para densidade de massa, condutividade térmica e capacidade térmica dos ovos (gema e clara) com base nos achados do artigo “Density, Heat Capacity and Thermal Conductivity of Liquid Egg Products”.
Em seguida, podemos regenerar e resolver a EDP como fizemos antes.
Regenere a equação diferencial parcial:
Resolva a EDP:
Verifique a faixa de temperatura da nova solução:
A faixa de temperatura resultante é razoável. Vamos visualizar a solução.
Crie os quadros para a solução:
Rasterize os quadros:
Anime os quadros:
Aqui vemos um aquecimento uniforme do ovo, semelhante à nossa última versão com apenas uma única região. No entanto, esta versão é mais precisa porque temos um modelo melhor da estrutura real do ovo.
Nesta solução, o resultado da temperatura de 38°C novamente parece muito baixo para o tempo fornecido. Na verdade, essa temperatura é ainda menor do que o resultado anterior de cerca de 42°C.
Precisamos de uma maneira de saber quais partes do ovo estão cozidas após um determinado tempo.
Versão 4: Refinar ainda mais o modelo
Versão 4: Refinar ainda mais o modelo
Nesta versão, vamos refinar os dados utilizados para as grandezas físicas envolvidas no modelo. Também iremos prever se o ovo está cozido, comparando os resultados com as temperaturas de desnaturação da gema e da clara (ou seja, as temperaturas em que as proteínas do ovo começam a se desenrolar e solidificar).
Para refinar as grandezas físicas (densidade, capacidade térmica e condutividade térmica), utilizaremos os dados fornecidos por estes dois estudos:
Na versão anterior, tínhamos boas estimativas das grandezas físicas tanto para a gema quanto para a clara do ovo. Mas, na realidade, essas grandezas podem mudar ao longo do tempo à medida que o ovo esquenta. Um modelo melhor é aquele que leva em conta como essas grandezas variam com a temperatura.
Utilizando dados dos estudos mencionados anteriormente, vamos configurar pares de temperaturas e a respectiva grandeza física (em unidades básicas do SI). Nosso objetivo é modelar cada grandeza física (densidade, condutividade térmica, capacidade térmica) como uma função da temperatura.
Vamos começar pela densidade. Observe que há uma definição de dados de densidade tanto para a gema quanto para a clara do ovo.
Vamos começar pela densidade. Observe que há uma definição de dados de densidade tanto para a gema quanto para a clara do ovo.
Configure os dados de medição para a densidade de massa da gema e da clara do ovo:
A opção "ExtrapolationHandler" é usada para lidar com pontos que estão fora do intervalo dos nossos dados disponíveis. Nossos dados não são perfeitos e não cobrem todo o intervalo de temperaturas. Como propriedades como a densidade variam quase linearmente, extrapolar a partir dos dados existentes fornece uma aproximação razoavelmente precisa.
Visualize os dados medidos e as funções interpoladas:
Podemos observar como a densidade diminui à medida que a temperatura aumenta. Embora não tenhamos dados de temperatura acima de 335 kelvins, temos uma extrapolação razoável a partir dos dados.
Agora repetimos o mesmo processo para a condutividade.
Configure os dados de medição para a condutividade térmica da gema e da clara do ovo:
Crie uma InterpolatingFunction para os dados de condutividade térmica:
Visualize os dados medidos e as funções interpoladas:
Podemos observar como a condutividade aumenta levemente com a temperatura e, novamente, temos uma extrapolação razoável dos dados.
Para a capacidade calorífica específica, temos uma abordagem um pouco diferente. Temos menos pontos de dados, e a qualidade desses pontos não é tão boa quanto para as outras duas quantidades. A abordagem ideal é fazer um ajuste linear dos dados, o que nos dará uma função linear que melhor se ajusta aos dados.
Configure os dados de medição para a capacidade calorífica da gema e da clara do ovo:
Para explorar com mais detalhes como a função funciona, consulte a documentação de LinearModelFit.
Visualize os dados medidos e a função linear que os ajusta:
O gráfico exibe uma aproximação razoável dos dados e uma boa extrapolação em temperaturas mais altas.
Agora que temos as funções para as grandezas físicas, só precisamos especificá-las como funções por partes, como fizemos antes:
Regenere a equação diferencial parcial:
Uma consideração importante: a densidade de massa, a condutividade térmica e a capacidade térmica agora são funções da temperatura T. Ao mesmo tempo, T é a variável dependente para a qual se busca uma solução. Essa dependência mútua significa que os coeficientes na equação variam com a própria solução, tornando a EDP não linear. Modelos não lineares normalmente exigem mais tempo e esforço computacional para serem resolvidos. Por isso, muitas vezes é uma boa ideia começar com uma malha não refinada ao configurar tudo. Uma vez obtida uma solução razoável, você pode alternar para uma malha refinada para obter maior precisão. No entanto, neste caso, vamos adiante e utilizaremos a malha refinada.
Agora resolvemos a PDE, monitoramos o progresso e medimos o tempo computacional e a memória utilizados (cerca de três minutos em um laptop comum).
Resolva a EDP:
Esse aumento no tempo de computação é esperado para a maioria dos modelos não lineares.
Verifique a faixa de temperatura da solução recém-encontrada:
Antes de visualizarmos nossa solução, definiremos as temperaturas de desnaturação da gema e da clara do ovo. Isso nos dará uma boa ideia se as duas regiões do ovo estão cozidas em determinado momento. Essas temperaturas são do estudo publicado no Journal of Food Measurement and Characterization citado anteriormente.
Defina a temperatura de desnaturação da clara de ovo:
Defina a temperatura de desnaturação para a gema de ovo:
Podemos visualizar as temperaturas de desnaturação juntamente com a animação da nossa solução. A melhor maneira de fazer isso é um gráfico de contorno com uma linha de contorno que indica o ponto na região com a temperatura de desnaturação.
Eu prefiro o gráfico de densidade, então aqui definimos uma nova função chamada TemperatureDenatureDensityPlot, que chama a função auxiliar definida anteriormente TemperatureDensityPlot. Estamos utilizando Show para exibir o gráfico como antes, mas com os contornos para as temperaturas de desnaturação da gema e da clara do ovo. Os contornos são plotados com um ContourPlot adicional.
Crie uma função auxiliar para gerar um gráfico de densidade da distribuição de temperatura e visualizar as temperaturas de desnaturação:
Crie os quadros para a solução:
Rasterize as quadros:
Anime os quadros:
A temperatura de desnaturação da clara do ovo é indicada pela linha tracejada verde, e a temperatura de desnaturação da gema do ovo é indicada pela linha tracejada magenta. O gráfico mostra a difusão de calor dentro do ovo, como esperado.
No marco dos seis minutos, podemos ver que toda a clara de ovo já ultrapassou sua temperatura de desnaturação. Este é um resultado promissor para o nosso modelo.
No entanto, se observarmos o ponto dos 10 minutos, toda a região ultrapassa a temperatura de desnaturação da clara de ovo, enquanto parte da gema ainda não ultrapassou a temperatura de desnaturação da gema, o que indica que a gema não está suficientemente cozida, mesmo após 10 minutos.
Ovos cozidos normalmente cozinham por 10–12 minutos, então 10 minutos devem resultar em uma gema completamente firme. Portanto, nosso modelo ainda não está completo, pois indica que após 10 minutos a gema não está totalmente cozida.
Verifique a temperatura de desnaturação da gema:
Nas versões 2 e 3 do modelo, obtivemos temperaturas de 38°C e 42°C, respectivamente. Aqui, na versão 4, obtemos cerca de 40°C para a temperatura no centro do ovo na marca de seis minutos. Comparado com a temperatura de desnaturação da gema, isso ainda parece muito baixo. Precisamos melhorar isso na próxima versão.
Versão 5: Construir uma Geometria Realista de Ovo
Versão 5: Construir uma Geometria Realista de Ovo
Quando o modelo não está nos dando a resposta que esperamos, pode ser uma boa ideia refiná-lo ainda mais. Uma maneira de fazer isso é analisar as suposições que fizemos. Uma suposição importante é que o ovo tem formato circular, o que, obviamente, não corresponde à realidade. Nesta versão, criaremos uma geometria mais realista para o ovo.
Ainda podemos supor que a geometria da gema do ovo é bem modelada por um círculo. Porém, podemos aproximar a geometria da casca do ovo de uma maneira mais realista.
Para fazer isso, usaremos uma equação matemática que aproxima a geometria da casca do ovo, com base nesta referência.
Crie uma função auxiliar para calcular as coordenadas da forma de uma geometria de ovo:
Manipule os parâmetros para visualizar diferentes formas:
Inspecione o valor do raio:
Vamos chamar a nova função eggShapePoints para um ovo que tem 5 cm de altura e 4 cm de largura.
Crie coordenadas para a geometria do ovo especificando parâmetros:
Crie uma spline:
Então podemos usar RegionUnion, unindo uma semicircunferência com nossa curva de casca de ovo, para criar o esqueleto da nossa região. Isso é exatamente como fizemos anteriormente, mas agora com a curva spline para a casca de ovo.
Crie uma geometria de ovo com uma sub-região:
Em seguida, criamos a malha com os marcadores de região, como fizemos anteriormente.
Crie uma malha com marcadores de material:
Visualize o marcador de elemento de ponto:
Como podemos ver, os marcadores para o exterior do ovo ainda são 2 e 5, portanto, não precisamos redefinir a condição de contorno.
Inspecione a condição de contorno:
Inspecione a refinementFunction:
Já estamos em um bom ponto, mas temos um pequeno problema. Para a nossa versão anterior, criamos uma função de refinamento baseada na região ter uma forma circular. Precisamos criar uma nova função de refinamento para a nossa nova região:
Podemos refinar os elementos com base na sua distância radial até a casca, que está mostrada como uma linha verde na imagem. O ponto vermelho representa um elemento e possui uma distância radial até o eixo de simetria (a linha azul) e uma distância radial até a casca.
Queremos definir uma função de refinamento baseada na distância em verde. Quanto maior a distância até a casca, menor o refinamento; quanto menor a distância até a casca, maior o refinamento. Além disso, para obter a distância da linha verde, subtraímos a distância da linha azul da distância do eixo de simetria até a casca do ovo (mostrada em magenta):
Primeiro, definimos uma função que retorna o valor da coordenada cilíndrica r para um dado z na curva da casca de ovo.
Faça uma interpolação das coordenadas da casca:
Estamos simplesmente invertendo a ordem dos pontos nas coordenadas da casca, substituindo {r, z} por {z, r}, e então fazendo uma interpolação a partir disso. Aqui, rShell é uma função de interpolação que recebe z e retorna r.
Represente graficamente a função que fornece a função rShell:
O gráfico desta função é o que esperaríamos: a coordenada r para a casca do ovo como função de z.
Então, a única outra coisa que precisamos fazer é calcular a distância do eixo até a casca menos o valor absoluto da coordenada r para cada ponto. Isso nos dará a distância de cada ponto até a casca (mostrada em verde):
Defina uma função para a distância radial até a casca e a plote:
O gráfico mostra que a distância de cada ponto até a superfície diminui quase linearmente, como seria de se esperar.
Plote a distância ao cubo até a casca:
Quando representamos a distância ao cubo, os valores diminuem mais rapidamente à medida que a distância até a casca se torna menor.
Lembre-se de que encontrar o comportamento correto para a função de refinamento é um processo de tentativa e erro.
Defina a função de refinamento:
Aqui definimos a refinementFunction de modo que um elemento seja refinado se sua área for maior que a distância até a casca elevada ao cubo, com um deslocamento para evitar refinar em excesso. Em outras palavras, o tamanho dos elementos é proporcional à distância até a casca elevada ao cubo. Quanto mais próximo da casca, menores são os elementos.
Visualize a malha de múltiplos materiais:
Como podemos ver, os elementos próximos ao centro do ovo não são refinados de forma alguma, mas obtemos um refinamento muito fino próximo à casca do ovo.
Podemos prosseguir para resolver a EDP como antes, medindo o tempo e a memória gastos. Esse cálculo de um modelo não linear com essa malha leva cerca de seis minutos para terminar (assim como os ovos que gosto de comer!). Mantenha o tempo de computação em mente ao desenvolver seus próprios modelos. É por isso que Monitor é útil, e por que utilizar uma malha não refinada no início é uma boa ideia.
Resolva a EDP, monitore o progresso e meça o tempo computacional e a memória utilizados:
Verifique a faixa de temperatura da solução recém-encontrada:
Novamente, obtemos uma faixa razoável de temperaturas, então podemos prosseguir com a animação.
Crie os quadros para a solução:
Rasterize as quadros:
Anime os quadros:
Dois pontos importantes: Primeiro, aos seis minutos, a gema do ovo ainda não está cozida, o que era algo esperado. Segundo, aos 10 minutos, toda a região já ultrapassou as temperaturas de desnaturação tanto da clara quanto da gema, portanto podemos assumir que o ovo está completamente cozido neste ponto. O modelo agora reflete um tempo realista para cozinhar o ovo. Ótimo!
Aos seis minutos, temos uma temperatura muito mais realista de quase 60°C no centro do ovo, em comparação com a nossa versão anterior do modelo, na qual o centro atingiu apenas cerca de 40°C. Podemos concluir que a geometria desempenha um papel crucial na dinâmica de aquecimento do ovo.
Versão 6: Use o Modelo
Versão 6: Use o Modelo
Agora que nosso modelo está produzindo resultados satisfatórios, podemos usá-lo para fazer previsões.
Anteriormente, nosso ovo foi introduzido em água fervente a partir da temperatura ambiente. Agora, vamos modelar um caso mais realista em que o ovo é retirado diretamente da geladeira, assumindo que o ovo tenha uma temperatura inicial de 8°C. Para modelar isso, precisamos modificar nossas condições iniciais e de contorno. Em particular, a condição de contorno precisa começar a partir da nova temperatura inicial e subir rapidamente até 100°C.
Primeiro, definimos a temperatura inicial para 8°C e a convertemos para kelvins.
Defina a temperatura inicial do ovo:
Em seguida, definimos nossa nova condição inicial.
Defina uma condição inicial para a temperatura dentro do ovo:
Também é necessário modificar a função de condição de contorno, que agora começa a partir da nova temperatura inicial.
Especifique o comportamento temporal da condição de contorno:
Visualize o comportamento temporal da condição de contorno:
Regenere a condição de contorno:
Em seguida, resolvemos a EDP como antes. Observe que, aqui, armazenamos nossa solução em uma nova variável chamada solutionFridge, para que possamos compará-la com nossa solução anterior.
Resolva a EDP, monitore o progresso e meça o tempo computacional e a memória utilizados:
Inspecione a faixa de temperatura da solução recém-encontrada:
Obtemos um intervalo que é razoável para o nosso ovo refrigerado.
Podemos plotar a solução da mesma forma que antes.
Crie os quadros para a solução:
Rasterize as quadros:
Anime os quadros:
Aos seis minutos, a gema do ovo ainda não está cozida, assim como na nossa última versão. Aos 10 minutos, o ovo parece estar completamente cozido. É difícil perceber apenas observando a animação se há alguma diferença significativa entre o ovo refrigerado e o ovo em temperatura ambiente.
Uma boa opção é traçar o gráfico da temperatura ao longo da linha que passa pelo centro da gema até a casca do ovo para ambas as soluções — o ovo refrigerado e o ovo em temperatura ambiente. Um gráfico mais simples pode revelar aspectos sutis que são difíceis de perceber no gráfico de densidade.
Estamos plotando a temperatura para os valores de r que estão sobre esta linha. Precisamos do valor de r para o limite direito. Com nossa função rShell que definimos anteriormente, podemos obter o valor da coordenada r para o valor de z igual a 0,005, que é o centro da gema do ovo.
Obtenha o valor de r para a reta:
Agora sabemos o valor de r para o limite direito da linha que nos interessa. Em seguida, queremos saber como a temperatura aumenta para essa linha, especificamente para os valores de r entre 0 e 0,0179. Podemos criar um gráfico simples, por exemplo, aos seis minutos, para esses valores de r.
Represente graficamente a solução ao longo da linha radial do centro da gema até o exterior do ovo aos seis minutos:
Podemos ver que a temperatura aos seis minutos é mais baixa para o ovo retirado diretamente da geladeira em comparação com o ovo à temperatura ambiente para todos os valores de r. Em particular, podemos observar uma diferença de cerca de 5°C no centro do ovo.
Como estamos interessados em prever se o ovo está cozido, também precisamos de uma maneira de visualizar a temperatura de desnaturação. Uma maneira de fazer isso é traçando uma linha vertical que marque o valor de r no qual o ovo atinge a temperatura de desnaturação.
Obtenha o valor de r no qual a solução é igual à temperatura de desnaturação:
Observamos que a temperatura de desnaturação da gema do ovo retirada da geladeira é atingida a um raio de aproximadamente 10 mm (1 cm) a partir do centro. Podemos representar isso com uma linha em nosso gráfico.
Represente graficamente a solução ao longo da linha radial do centro da gema até o exterior do ovo:
Além da gema de ovo, também precisamos da temperatura de desnaturação da clara de ovo tanto para o ovo em temperatura ambiente quanto para o ovo refrigerado. Em vez de fazer isso manualmente, podemos definir uma função auxiliar.
Esta função recebe a solução e o valor da temperatura de desnaturação de nosso interesse, depois utiliza FindRoot para determinar o raio ao longo da linha plotada no qual a temperatura de desnaturação ocorre. Por fim, retorna uma linha vertical, que podemos exibir no gráfico.
Escreva uma função auxiliar para criar uma linha da temperatura de desnaturação de uma solução:
Em seguida, criamos uma função para o gráfico propriamente dito, onde usamos Show para exibir o gráfico e as linhas das temperaturas de desnaturação, chamando nossa função auxiliar denatureLine e também uma linha indicando o raio da gema do ovo.
Crie uma função auxiliar para plotar as posições de desnaturação para as duas soluções em vários momentos:
Ao observar o gráfico no marco dos seis minutos, notamos duas coisas. Primeiro, fica claro que a desnaturação da clara já avançou bastante em direção ao centro do ovo. Segundo, a temperatura de desnaturação da gema chegou muito mais perto do centro no caso do ovo em temperatura ambiente em comparação com o ovo refrigerado.
O que isso significa? No caso do ovo em temperatura ambiente, a gema está apenas começando a cozinhar. Mas, para o ovo refrigerado, a gema ainda está líquida — a temperatura de desnaturação mal chegou à borda da gema.
Portanto, se quisermos uma gema mole, temos duas opções:
1
.Use um ovo refrigerado e retire-o da água fervente exatamente aos seis minutos
2
.Use um ovo em temperatura ambiente e retire-o da água alguns segundos antes
Se fizermos o mesmo gráfico, mas para oito minutos, veremos algo interessante. Por volta de oito minutos, todo o ovo à temperatura ambiente já ultrapassou a temperatura de desnaturação da gema, o que significa que também ultrapassou a temperatura de desnaturação da clara do ovo. Mas ainda há algumas partes da gema do ovo refrigerado que ainda não atingiram essa temperatura.
O que isso significa? Se você quiser uma gema totalmente cozida e estiver usando um ovo direto da geladeira, deixe-o na água fervente por alguns segundos além dos oito minutos. Se estiver usando um ovo em temperatura ambiente — e estiver com fome e não quiser esperar — oito minutos podem ser tempo suficiente.
Tudo se resume a isto
Tudo se resume a isto
Começamos criando uma primeira versão simples, apenas algo para colocar nosso fluxo de trabalho em funcionamento. Se pulamos diretamente para programar um modelo complexo, é muito mais provável que cometamos erros. O pior é que esses erros podem ser difíceis de identificar. Se os resultados não parecerem corretos, nem sempre fica claro se há um problema no próprio modelo ou se apenas cometemos um erro no código.
Ao começar de forma simples e adicionar complexidade gradualmente, passo a passo, reduzimos a chance de introduzir erros. Também obtemos uma compreensão muito melhor de como o nosso modelo se comporta.
Como vimos, o salto repentino de temperatura entre o exterior e o interior do ovo estava causando problemas numéricos em uma das primeiras versões do nosso modelo. Para resolver isso, refinamos a malha exatamente na fronteira usando uma função de refinamento. Esse método é muito melhor do que refinar toda a malha, pois isso deixaria nosso cálculo significativamente mais lento.
Por fim, utilizamos dados experimentais de duas maneiras. Primeiro, usamos os dados experimentais para construir nosso modelo, ajustando os parâmetros na equação do calor. Em segundo lugar, empregamos os dados para comparar nossos resultados com os tempos reais de cozimento de ovos de verdade.
Podemos concluir algumas coisas:
◼
Criar primeiro uma versão simples é uma boa ideia.
◼
Aumentar a complexidade do modelo passo a passo pode facilitar as coisas.
◼
Transições abruptas ou descontinuidades nas variáveis da solução podem causar instabilidade numérica ou perda de precisão. Use refinamento local de malha ou suavização nessas regiões.
◼
Ter uma maneira de comparar nossos resultados com dados do mundo real é útil.
Por fim, se você achou isto interessante e deseja implementar seus próprios modelos de PDE, confira esta Visão Geral de PDEModels na documentação.