You have 100kg of potatoes, which are 99% water by weight. You let them dehydrate until they’re 98% water. How much do they weigh now?
All’inizio abbiamo kg di patate, di cui il è acqua, quindi la massa di acqua è e la massa di sostanza secca è .
Dopo la disidratazione, la percentuale di acqua nelle patate scende al . Chiamiamo la massa totale delle patate dopo la disidratazione. La massa di acqua sarà ora e la massa di sostanza secca rimarrà invariata, ovvero , poiché la sostanza secca non viene influenzata dalla disidratazione.
Possiamo ora impostare l’equazione per la massa totale delle patate dopo la disidratazione:
Ovvero:
Quindi, le patate pesano ora . Il risultato può sembrare controintuitivo perché una piccola percentuale di disidratazione risulta in una riduzione del peso totale di 50 kg, ma matematicamente ha senso come abbiamo visto sopra.
Il Lattice Boltzmann Method (LBM) è una tecnica potente e versatile per la simulazione numerica dei fluidi. Si distingue per la sua capacità di gestire complesse condizioni al contorno e per la relativa facilità di implementazione, rispetto ad altri metodi computazionali. Esploreremo, brevemente, la metodologia LBM attraverso una specifica implementazione: la simulazione del flusso bidimensionale attorno a un cilindro.
Il cuore del metodo LBM è l’equazione di Boltzmann discretizzata nello spazio, nel tempo e nelle velocità. In particolare, il modello D2Q9, che utilizza nove direzioni di velocità in uno spazio bidimensionale, è una scelta comune per via della sua semplicità e accuratezza. L’equazione di Boltzmann discretizzata è implementata per evolvere la funzione di distribuzione delle particelle nel reticolo.
import numpy as np
from numpy import fromfunction, roll
from numpy.linalg import norm
import matplotlib.pyplot as plt
from matplotlib import cm
import imageio
import os
# Parametri del problema
maxIter = 200000 # Numero totale di iterazioni temporali
Re = 220.0 # Numero di Reynolds
nx, ny = 520, 180 # Dimensioni della griglia
ly = ny - 1.0
q = 9 # Numero di popolazioni in ciascuna direzione
cx, cy, r = nx // 4, ny // 2, ny // 9 # Coordinate del cilindro
uLB = 0.04 # Velocità in unità di griglia
nulb = uLB * r / Re # Viscosità in unità di griglia
omega = 1.0 / (3.0 * nulb + 0.5) # Parametro di rilassamento
# Costanti del reticolo
c = np.array([(x, y) for x in [0, -1, 1] for y in [0, -1, 1]]) # Velocità del reticolo
t = 1.0 / 36.0 * np.ones(q) # Pesi del reticolo
t[np.asarray([norm(ci) < 1.1 for ci in c])] = 1.0 / 9.0
t[0] = 4.0 / 9.0
noslip = [c.tolist().index((-c[i]).tolist()) for i in range(q)] # Indice delle condizioni di non scorrimento
i1 = np.arange(q)[np.asarray([ci[0] < 0 for ci in c])] # Parete destra
i2 = np.arange(q)[np.asarray([ci[0] == 0 for ci in c])] # Parete centrale verticale
i3 = np.arange(q)[np.asarray([ci[0] > 0 for ci in c])] # Parete sinistra
# Funzioni di supporto
def sumpop(fin):
return np.sum(fin, axis=0)
def equilibrium(rho, u): # Funzione di equilibrio
cu = 3.0 * np.dot(c, u.transpose(1, 0, 2))
usqr = 3.0 / 2.0 * (u[0] ** 2 + u[1] ** 2)
feq = np.zeros((q, nx, ny))
for i in range(q):
feq[i, :, :] = rho * t[i] * (1.0 + cu[i] + 0.5 * cu[i] ** 2 - usqr)
return feq
# Inizializzazione
obstacle = fromfunction(lambda x, y: (x - cx) ** 2 + (y - cy) ** 2 < r ** 2, (nx, ny))
vel = fromfunction(lambda d, x, y: (1 - d) * uLB * (1.0 + 1e-4 * np.sin(y / ly * 2 * np.pi)), (2, nx, ny))
feq = equilibrium(1.0, vel)
fin = feq.copy()
# Percorsi delle immagini e della GIF
image_paths = []
# Loop principale
for time in range(maxIter):
# Condizione di uscita
fin[i1, -1, :] = fin[i1, -2, :]
rho = sumpop(fin)
u = np.dot(c.transpose(), fin.transpose((1, 0, 2))) / rho
# Parete sinistra: calcolo della densità
u[:, 0, :] = vel[:, 0, :]
rho[0, :] = 1.0 / (1.0 - u[0, 0, :]) * (sumpop(fin[i2, 0, :]) + 2.0 * sumpop(fin[i1, 0, :]))
# Condizione di Zou/He
feq = equilibrium(rho, u)
fin[i3, 0, :] = fin[i1, 0, :] + feq[i3, 0, :] - fin[i1, 0, :]
# Collisione
fout = fin - omega * (fin - feq)
for i in range(q):
fout[i, obstacle] = fin[noslip[i], obstacle]
# Streaming
for i in range(q):
fin[i, :, :] = roll(roll(fout[i, :, :], c[i, 0], axis=0), c[i, 1], axis=1)
# Visualizzazione e salvataggio immagini
if time % 100 == 0:
plt.clf()
img_path = "vel." + str(time // 100).zfill(4) + ".png"
plt.imshow(np.sqrt(u[0] ** 2 + u[1] ** 2).transpose(), cmap=cm.Reds)
plt.savefig(img_path)
image_paths.append(img_path)
# Creazione della GIF
with imageio.get_writer('flow_simulation.gif', mode='I') as writer:
for img_path in image_paths:
image = imageio.imread(img_path)
writer.append_data(image)
# Rimozione delle immagini
for img_path in image_paths:
os.remove(img_path)
Il codice Python fornito implementa la simulazione LBM per il flusso attorno a un cilindro in 2D. Esaminiamo il codice passo dopo passo per vedere come i concetti di LBM sono tradotti in programmazione.
Inizializzazione
Il codice inizia con l’importazione dei moduli necessari e la definizione dei parametri di simulazione:
from numpy import *; from numpy.linalg import *
import matplotlib.pyplot as plt; from matplotlib import cm
maxIter = 200000 # Numero totale di iterazioni temporali.
Re = 220.0 # Numero di Reynolds.
La scelta di maxIter e Re determina rispettivamente la durata della simulazione e il regime di flusso. Il numero di Reynolds è particolarmente critico poiché definisce la transizione tra flusso laminare e turbolento.
Definizione del Reticolo e Parametri di Flusso
nx = 520; ny = 180; ... # Dimensioni del reticolo e popolazioni.
uLB = 0.04 # Velocità in unità di reticolo.
nulb = uLB*r/Re; omega = 1.0 / (3.*nulb+0.5); # Parametro di rilassamento.
La definizione delle dimensioni del reticolo (nx, ny) e del parametro uLB stabilisce il quadro della simulazione. Il parametro di rilassamento omega è derivato dalla viscosità e gioca un ruolo cruciale nell’equazione di evoluzione.
Configurazione del Reticolo e Condizioni al Contorno
Il cilindro viene modellato e le condizioni al contorno vengono stabilite:
obstacle = fromfunction(lambda x,y: (x-cx)**2+(y-cy)**2<r**2, (nx,ny))
vel = fromfunction(lambda d,x,y: (1-d)*uLB*(1.0+1e-4*sin(y/ly*2*pi)), (2,nx,ny))
feq = equilibrium(1.0, vel); fin = feq.copy()
obstacle rappresenta la posizione del cilindro nel reticolo, mentre vel stabilisce il profilo di velocità in ingresso, fondamentale per l’innesco del flusso.
Ciclo Principale di Simulazione
Il nucleo della simulazione è un ciclo che aggiorna le funzioni di distribuzione secondo l’equazione di Lattice Boltzmann:
for time in range(maxIter):
... # Condizioni al contorno
... # Passo di collisione
... # Passo di streaming
Qui, la dinamica del flusso è simulata con passi sequenziali che includono la gestione delle condizioni al contorno (come l’uscita del flusso e il movimento del muro), la collisione (aggiornamento delle funzioni di distribuzione verso l’equilibrio), e lo streaming (spostamento delle funzioni di distribuzione attraverso il reticolo).
L’implementazione fornita illustra chiaramente come i principi teorici di LBM siano incorporati in un contesto di simulazione pratica. Questa specifica simulazione LBM ci fornisce un esempio concreto di come metodi computazionali avanzati possano essere utilizzati per investigare fenomeni fisici complessi in modo relativamente semplice e intuitivo. Attraverso un’adeguata sintonizzazione dei parametri e delle condizioni iniziali, il metodo Lattice Boltzmann si rivela uno strumento potentissimo nell’analisi e nella visualizzazione dei flussi fluidi, sia in contesti accademici che industriali.
The Logistic Equation serves as a ubiquitous model in several scientific disciplines to depict population growth within a resource-constrained environment. This article delves into how Python, aided by the SymPy, NumPy, and Matplotlib libraries, can efficiently tackle this equation both analytically and numerically.
The Logistic Equation
The Logistic Equation is mathematically expressed as:
Where:
P represents the population,
tis the time,
ris the growth rate,
Kis the carrying capacity of the environment.
Analytical Solution with SymPy
To ascertain the analytical solution, one can leverage the symbolic computation capabilities of the SymPy library.
Import Libraries and Define Variables
Firstly, SymPy is imported and the necessary variables are defined.
from sympy import symbols, Function, Eq, dsolve
t = symbols('t')
P = Function('P')(t)
r, K = symbols('r K')
logistic_eq = Eq(P.diff(t), r * P * (1 - P/K))
Integration and Solution
The general solution of the logistic equation can be found via integration:
Using SymPy, the analytical solution can be obtained as:
analytical_solution = dsolve(logistic_eq)
The analytical solution is:
Where is an integration constant.
Numerical Solution with NumPy and Matplotlib
For a numerical solution, the Euler method can be employed to approximate the solution to the differential equation. NumPy is used for the computations and Matplotlib for visualization.
A comparison between the two solutions confirms the accuracy of the numerical model. To do this, the numerical solution can be overlaid onto the analytically calculated values.
# Code to calculate and plot the analytical solution for a subset of points
# ...
plt.plot(time_reduced, P_analytical_reduced_real, label='Analytical Solution', linestyle='dashed')
plt.scatter(time, P_numerical, color='red', s=10, label='Numerical Solution')
plt.legend()
plt.grid(True)
plt.show()
Conclusion
We have observed that Python, with specialized libraries like SymPy, NumPy, and Matplotlib, can be a powerful tool for both analytical and numerical analysis of differential equations. Specifically, the logistic equation was solved using analytical and numerical methods, providing a complete understanding of population dynamics in a resource-limited setting.
This hybrid approach, blending analytical and numerical analysis, offers a robust strategy for understanding and solving complex problems across various applied science fields.
In un mondo dove l’innocenza è una gemma rara, la perdita di essa è una tragedia incommensurabile. Rapito, il capolavoro di Marco Bellocchio, si immerge nell’oscura acqua di una storia vera, quella del giovane Edgardo Mortara, un bambino ebreo sottratto all’affetto familiare, trainato nelle spire del potere ecclesiastico del Papa Pio IX, interpretato con una carica inquietante da Paolo Pierobon.
In una società dove la religione e la politica si intrecciano, formando una ragnatela spesso soffocante, il piccolo Edgardo diventa simbolo di una lotta silente, quella dell’identità personale contro l’invadente potere che vuole plasmarla. In questa narrazione, Bellocchio non solo racconta una storia del passato, ma specchia le angosce contemporanee di un’Italia ancora stretta tra gli artigli di poteri che negano l’evoluzione, che temono il cambiamento.
La lente di Bellocchio, attenta e impavida, si posa sulle figure che orbitano attorno al giovane protagonista, dipingendo con tocchi sensibili ma decisi, l’umanità straziante dei genitori, interpretati con toccante autenticità da Fausto Maria Alesi e Barbara Ronchi. È un mondo plumbeo quello di Rapito, dove le ombre sembrano avere vita propria, raccontate dalla fotografia evocativa di Francesco Di Giacomo.
Non siamo che il risultato dell’ambiente che ci circonda, e Bellocchio esplora la metamorfosi del piccolo Edgardo con una delicatezza che tocca le corde più profonde. In questa trasformazione, il giovane scopre nuovi orizzonti, ma al prezzo di una perdita incolmabile, quella delle radici che lo ancoravano a una realtà ora lontana.
Rapito diventa così non solo una riflessione sulla fede e il potere, ma una meditazione più ampia sull’identità, sul conflitto tra chi siamo e chi ci viene chiesto di essere. È un viaggio nel cuore oscuro dell’umanità, un viaggio che Bellocchio intraprende con una maestria narrativa che pochi possono eguagliare. La storia di Edgardo Mortara risuona attraverso i secoli, un monito delicato ma ferreo sul valore della libertà individuale, sul diritto inalienabile di ogni essere umano di scegliere il proprio destino, di rimanere ancorato alla propria identità anche quando le tempeste della vita tentano di sradicarlo. Con Rapito, Bellocchio non solo ci regala una perla cinematografica, ma ci invita a riflettere, a guardare oltre le apparenze, a cercare quella scintilla di libertà che risiede in ognuno di noi, anche quando il mondo esterno tenta di soffocarla. In questo senso, Rapito non è solo un film, ma una esperienza emotiva e intellettuale, un viaggio nel profondo dell’anima umana che lascia un segno indelebile.
La ricerca degli zeri di una funzione è un problema centrale in matematica applicata e ingegneria. Esistono vari metodi per affrontare questa sfida, dal più semplice metodo della bisezione al più avanzato metodo di Newton-Raphson. In questo articolo, ci concentreremo sul metodo di Halley, un’estensione del metodo di Newton-Raphson, che presenta una convergenza più rapida sotto determinate condizioni. Dopo una presentazione teorica del metodo, forniremo un’implementazione in Python utilizzando la libreria NumPy, con particolare attenzione alla vettorizzazione per aumentare l’efficienza computazionale.
Formula del Metodo di Halley
Il metodo di Halley è definito dalla seguente formula iterativa:
Il metodo di Halley utilizza un’approssimazione della funzione basata sulla sua serie di Taylor troncata al secondo ordine:
Risolvendo per quando è approssimato a zero, otteniamo la formula iterativa del metodo di Halley.
La forza di Python risiede nella sua ampia gamma di librerie di supporto. In questo caso, useremo NumPy per la manipolazione di array e per l’implementazione vettorizzata del nostro algoritmo.
Ecco un estratto del codice Python che implementa il metodo di Halley:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
# Generazione del polinomio
p = np.polynomial.Polynomial(np.random.choice([-1., 1., 1.j, -1.j], 30))
dp = p.deriv()
ddp = dp.deriv()
def halley_method(z):
return z - p(z) / (dp(z) - ddp(z) * p(z) / (2 * dp(z))), z
Dettagli dell’Implementazione
Generazione del Polinomio: Utilizziamo la classe Polynomial di NumPy per generare un polinomio con coefficienti casuali.
Calcolo delle Derivate: dp e ddp sono le prime e seconde derivate del polinomio. NumPy fornisce un metodo deriv() per questo scopo.
Metodo di Halley Vettorizzato: La funzione halley_method(z) implementa il metodo di Halley in modo vettorizzato. Grazie a NumPy, l’operazione viene eseguita su ogni elemento dell’array z simultaneamente.
La vettorizzazione è un concetto chiave per migliorare l’efficienza. Invece di utilizzare un ciclo per applicare la formula di Halley a ciascun punto, operiamo su tutto l’array z contemporaneamente. Questo è possibile perché NumPy è ottimizzato per eseguire operazioni vettorizzate in modo efficiente.
Il metodo di Halley, in conclusione, offre un modo efficace per trovare gli zeri di una funzione con una velocità di convergenza generalmente superiore a quella del metodo di Newton-Raphson, a costo di una maggiore complessità computazionale dovuta al calcolo della seconda derivata. L’implementazione in Python sfrutta la potenza della vettorizzazione tramite NumPy, offrendo un codice sia efficiente che conciso.
L’immagine generata dal codice rappresenta una visualizzazione delle radici del polinomio in questione nel piano complesso. In particolare, l’immagine è costruita usando il metodo di Halley per trovare le radici, e il colore di ciascun punto nel piano complesso è determinato dal numero di iterazioni necessarie per arrivare a una soluzione approssimata entro una certa tolleranza.
In termini tecnici:
L’asse x rappresenta la parte reale del numero complesso, mentre l’asse y rappresenta la parte immaginaria.
Ogni punto del piano complesso inizia con un valore iniziale (z), che è iterativamente aggiornato usando il metodo di Halley fino a quando non si raggiunge una soluzione approssimata o si supera un numero massimo di iterazioni.
Il colore del punto rappresenta il numero di iterazioni effettuate. Un colore che rappresenta un numero minore di iterazioni indica che il punto iniziale era più vicino a una radice del polinomio. In altre parole, regioni dell’immagine con colori simili sono vicine alla stessa radice del polinomio.
In pratica, questa visualizzazione fornisce un modo intuitivo per vedere dove si trovano le radici di un polinomio nel piano complesso e come la convergenza al valore della radice varia a seconda del punto di partenza. Essa può fornire intuizioni utili sulla distribuzione delle radici e sulla robustezza del metodo di Halley nel trovare tali radici da diverse condizioni iniziali.
The world of topology brings with it the fascination of non-orientable surfaces, one of which is the Klein bottle. Unlike the Möbius strip, which is a surface with a single boundary, the Klein bottle has no boundary. Intriguingly, in a three-dimensional space, the Klein bottle cannot exist without intersecting itself. However, in a four-dimensional space, it does not intersect itself. A crucial feature of the Klein bottle is its non-orientability, meaning it has only one side.
Parametrization of the Klein Bottle
To visualize the Klein bottle in a three-dimensional space, one can employ a parametric representation. A possible parametric formula for the Klein bottle in terms of parameters (u) and (v) is:
Using these equations, one can plot points in a 3D space corresponding to various values of
and , thus obtaining a representation of the Klein bottle.
Power of Plotly for Interactive 3D Visualization
Plotly, a Python graphing library, makes it effortless to create interactive visual representations. One of its strengths is the ability to craft 3D plots that users can rotate, zoom, and pan, offering an immersive experience when understanding complex shapes like the Klein bottle.
Here’s a code snippet that uses Plotly to visualize the Klein bottle:
import numpy as np
import plotly.graph_objects as go
def klein_bottle_parametrization(u, v):
x = -(4 - 2*np.cos(u)) * np.cos(v) + 6 * (np.sin(u) + 1) * np.cos(u)
y = 16 * np.sin(u)
z = (4 - 2*np.cos(u)) * np.sin(v)
return x, y, z
# Generating parameters u and v
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, 2 * np.pi, 50)
U, V = np.meshgrid(u, v)
# Calculating x, y, z coordinates
X, Y, Z = klein_bottle_parametrization(U, V)
# Creating a 3D Plot with Plotly
fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y, colorscale='Viridis', cmin=-30, cmax=30)])
# Displaying the plot
fig.show()
Upon execution, this script provides an interactive 3D representation of the Klein bottle. With Plotly’s interactive capabilities, users can explore the intricacies of the Klein bottle from different angles and perspectives, aiding in the comprehension of its unique topology.
The Klein bottle, in conclusion, with its singular properties, is a captivating subject in topology. While its true non-intersecting form exists in four-dimensional space, visualizing it in three dimensions offers valuable insights. Using tools like Plotly enhances this visualization experience by allowing interactive engagement, making it easier to grasp and appreciate the complexities of such mathematical objects.
Nel silente scorrere del tempo, le immagini catturate dalla lente di Giovanni Chiaramonte raccontano di luoghi e destini intrecciati. Ogni scatto, un dialogo tra il visibile e l’invisibile, una poesia di luci e ombre. Nel dolce abbraccio della fotografia, Chiaramonte ha tracciato il sentiero di un’esplorazione senza tempo, dove il reale si fonde con l’etereo. Ogni fotografia, un frammento di eternità, una finestra aperta sul profondo respiro dell’esistenza. Le sue immagini, sospese tra cielo e terra, raccontano di un viaggio che va oltre il mero vedere, invitando a una meditazione profonda sul nostro posto nel disegno più ampio. L’arte di Chiaramonte non era mera rappresentazione, ma un invito a penetrare il velo della superficie, a cercare il divino nel quotidiano. Un filosofo della lente, un poeta del silenzio che, con grazia e umiltà, ha indagato i misteri del visibile e dell’invisibile. Con la sua scomparsa, noi tutti perdiamo un maestro che ha saputo esprimere, attraverso il diaframma della sua macchina fotografica, la profonda relazione tra l’essere e lo spazio, il sacro e il profano. Ma il suo lascito continua a vivere, nelle immagini che hanno catturato l’infinito in un battito di ciglia, nel silente dialogo tra luce e ombra che continua a narrare la bellezza della vita, nella semplicità profonda che ha guidato ogni suo scatto. Giovanni Chiaramonte, con la sua arte, ha tracciato un sentiero di luce nel cuore dell’oscurità, un invito a vedere oltre, a cercare il bello anche nell’effimero, a riconoscere l’eterno nel transitorio.
La trama di “The Orphanage” si disvela come il filo di Arianna che guida verso il labirinto delle emozioni umane, i suoi spettri e le sue ombre. Si narra di un ritorno, di una madre, Laura, che torna nel luogo dove l’infanzia l’aveva accolta con braccia invisibili, un orfanotrofio, portando con sé il seme della speranza e del dolore: il piccolo Simon, un bimbo segnato da un destino infausto, il virus dell’HIV. Con il marito Carlos, Laura vuole infondere nuova vita in quel luogo, farlo rifiorire come un giardino accogliente per bambini bisognosi di cure e affetto. La narrazione si muove sull’asse sottile tra la realtà palpabile e quella invisibile, sfiorando il soprannaturale con la delicatezza di una foglia che cade in autunno. Simon, il piccolo, vede ciò che agli occhi degli adulti è negato, amici immaginari che lasciano tracce tangibili sul terreno. La tensione cresce come un fiume in piena, fino al giorno in cui l’anziana assistente sociale giunge con un dossier sul piccolo, e la stessa donna è poi sorpresa nelle tenebre notturne a vagare vicino al magazzino degli attrezzi. Un mistero che si infittisce, una madre che si fa cacciatrice di verità, di tracce, di risposte. La tragedia si consuma in una festa, Simon scompare, inghiottito da un vortice di domande senza risposta. L’abisso dell’angoscia si spalanca sotto i piedi di Laura. E’ il dolore straziante di una madre che cerca, che chiama, che spera. E’ un viaggio nel buio, un tuffo nel passato che risorge con i suoi fantasmi. Juan Antonio Bayona, sotto l’ala protettiva di Guillermo del Toro, scolpisce questo racconto con una maestria che risiede nel non detto, nel suggerito, nel velato. Il pubblico è diviso, tra chi vede echi di storie già viste e chi si lascia invece catturare dalla raffinatezza del racconto, dalla profondità delle emozioni in esso incise. La magistrale interpretazione di Belén Rueda eleva il film oltre i confini del genere horror, rendendolo un’indagine psicologica che esplora il dolore, la perdita, la speranza. Il film si snoda tra le stanze silenziose dell’ex orfanotrofio, tra echi di voci infantili e il freddo marmo della realtà. E’ un canto di dolore e di amore, un’ode alla resilienza umana, un viaggio attraverso i meandri dell’anima dove ogni angolo può nascondere un sorriso o un terrore inimmaginabile. Il brivido sottile dell’ignoto si mescola alla dolce melodia della speranza in una danza che lascia il segno, che interpella l’animo umano nelle sue profondità più oscure e nei suoi slanci più luminosi.
La prospettiva attraverso un vetro rotto sospende il presente e risveglia il passato. Mostra la vita come un insieme di istanti che il tempo dissolve..