Modellierung vun ana fließenden nit-viskosn Flüssigkeit mit QUICK-PDE
Qiskit Functions san a experimentelle Funktion, de nur für Benutzer vum IBM Quantum ® Premium Plan, Flex Plan und On-Prem (via IBM Quantum Platform API) Plan verfügbar is. Se san im Preview-Release-Status und kenna sich ändern.
Nutzungsschätzung: 50 Minutn auf am Heron r2-Prozessor. (HINWEIS: Des is nur a Schätzung. Ihre Laufzeit kann variiern.)
Beachts, dass de Ausführungszeit vun dera Funktion im Allgemeinen mehr als 20 Minutn beträgt, drum mögst vielleicht des Tutorial in zwoa Abschnitt aufteilen: an erschtn, wo mia's durchlesn und de Jobs startn, und an zweitn a paar Stundn später (damit de Jobs gnua Zeit zur Fertigstellung ham), um mit de Ergebniss vun de Jobs z'arbeiten.
Hintergrund
Des Tutorial is dazu do, auf einführendem Niveau z'zeigen, wie mia de QUICK-PDE-Funktion verwenden kenna, um komplexe Multi-Physik-Probleme auf 156Q Heron R2 QPUs unter Verwendung vum ColibriTDs H-DES (Hybrid Differential Equation Solver) z'lösen. Da zugrunde liegende Algorithmus is im H-DES-Paper beschrieben. Beachts, dass dera Solver au nit-lineare Gleichungen lösen kann.
Multi-Physik-Probleme – darunter Strömungsdynamik, Wärmediffusion und Materialverformung, um nur a paar z'nennen – kenna überall durch partielle Differentialgleichungen (PDEs) beschrieben wern.
Selle Probleme san für verschiedene Industrien hochrelevant und stelln an wichtigen Zweig vun da angewandtn Mathematik dar. De Lösung vun nit-lineare multivariaten gekoppelten PDEs mit klassischen Werkzeign bleibt aber wegen da Anforderung vun ana exponentiell großn Menge an Ressourcen schwierig.
Dise Funktion is für Gleichungen mit zunehmender Komplexität und Variablen geeignet und is da erschte Schritt, um Möglichkeiten z'erschließen, de amol als unlösbar göltn. Um a durch PDEs modelliertes Problem vollständig z'beschreiben, is es nötig, de Anfangs- und Randbedingungen z'kennen. De kenna de Lösung vun da PDE und da Weg zur Findung ihrer Lösung stark verändernm.
Des Tutorial zeigt eich, wie mia:
- De Parameter vun da Anfangsbedingungsfunktion definieren.
- De Qubit-Anzahl (verwendet zur Codierung vun da Funktion vun da Differentialgleichung), Tiefe und Shot-Anzahl anpassen.
- QUICK-PDE ausführen, um de zugrunde liegende Differentialgleichung z'lösen.
Anforderungen
Stellt's vor dem Anfang vun diesem Tutorial sicher, dass mia Folgendes installiert ham:
- Qiskit SDK v2.0 oder höher (
pip install qiskit) - Qiskit Functions Catalog (
pip install qiskit-ibm-catalog) - Matplotlib (
pip install matplotlib) - Zugang zur QUICK-PDE-Funktion. Füllt's des Formular aus, um Zugang anzufordern.
Setup
Authentifiziert's eich mit euerm API-Schlüssel und wählt's de Funktion so aus:
import numpy as np
import matplotlib.pyplot as plt
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(
channel="ibm_quantum_platform",
instance="INSTANCE_CRN",
token="YOUR_API_KEY", # Use the 44-character API_KEY you created and saved from the IBM Quantum Platform Home dashboard
)
quick = catalog.load("colibritd/quick-pde")
Schritt 1: Eigenschaftn vum z'lösenden Problem festlegn
Des Tutorial behandelt de Benutzererfahrung aus zwoa Perspektivn: des physikalische Problem, des durch de Anfangsbedingungen bestimmt wird, und de algorithmische Komponente zur Lösung vun am Strömungsdynamikbeispiel auf am Quantencomputer.
Computational Fluid Dynamics (CFD) hat a breits Anwendungsspektrum, und drum is es wichtig, de zugrunde liegenden PDEs z'studieren und z'lösen. A wichtige Familie vun PDEs san de Navier-Stokes-Gleichungen, des san a System nichtlinearer partieller Differentialgleichungen, de de Bewegung vun Flüssigkeiten beschreibn. Se san hochrelevant für wissenschaftliche Probleme und technische Anwendungen.
Unter bestimmten Bedingungen reduzieren sich de Navier-Stokes-Gleichungen auf de Burgers-Gleichung, a Konvektions-Diffusions-Gleichung, de Phänomene beschreibt, de in Strömungsdynamik, Gasdynamik und nichtlinearer Akustik auftretn, um nur a paar z'nennen, indem se dissipative Systeme modelliert.
De eindimensionale Version vun da Gleichung hängt vun zwoa Variablen ab: modelliert de zeitliche Dimension, repräsentiert de räumliche Dimension. De allgemeine Form vun da Gleichung wird de viskose Burgers-Gleichung gnennt und lautet:
wobei des Fluidgeschwindigkeitsfeld an ana gegebenen Position und Zeit is, und de Viskosität vun da Flüssigkeit is. Viskosität is a wichtige Eigenschaft vun ana Flüssigkeit, de ihren ratenabhängigen Widerstand gegen Bewegung oder Verformung misst, und drum spielt se a entscheidende Rolle bei da Bestimmung vun da Dynamik vun ana Flüssigkeit. Wenn de Viskosität vun da Flüssigkeit null is ( = 0), wird de Gleichung zu ana Erhaltungsgleichung, de Diskontinuitäten (Stoßwelln) entwickeln kann, weil's kan innern Widerstand ham. In dem Fall wird de Gleichung als inviskose Burgers-Gleichung bezeichnet und is a Spezialfall vun ana nichtlinearen Wellengleichung.
Streng gnommen treten inviskose Strömungen in da Natur ned auf, aber bei da Modellierung aerodynamischer Strömungen kann de Verwendung vun ana inviskosen Beschreibung vum Problem wegen dem infinitesimalen Transporteffekt nützlich sei. Überraschenderweise befasst sich mehr als 70% vun da aerodynamischen Theorie mit inviskosen Strömungen.
Des Tutorial verwendet de inviskose Burgers-Gleichung als CFD-Beispiel zur Lösung auf IBM® QPUs mit QUICK-PDE, gebn durch de Gleichung:
De Anfangsbedingung für des Problem is auf a lineare Funktion gsetzt: wobei und beliebige Konstantn san, de de Form vun da Lösung beeinflussn. Mia kenna und anpassen und schaugn, wie se da Lösungsprozess und de Lösung beeinflussn.
job = quick.run(
use_case="cfd",
physical_parameters={"a": 1.0, "b": 1.0},
)
print(job.result())
{'functions': {'u': array([[1. , 0.96112378, 0.9230742 , 0.88616096, 0.85058445,
0.81644741, 0.78376878, 0.75249908, 0.72253689, 0.69374562,
0.66597013, 0.63905258, 0.61284684, 0.58723093, 0.56211691,
0.53745752, 0.51324915, 0.48953036, 0.46637547, 0.44388257,
0.4221554 , 0.40127848, 0.38128488, 0.36211604, 0.34357308,
0.32525895, 0.30651089, 0.28632252, 0.26325504, 0.23533692],
[1.2375 , 1.19267729, 1.14850734, 1.10544526, 1.06382155,
1.02385326, 0.98565757, 0.94926734, 0.91464784, 0.88171402,
0.85034771, 0.82041411, 0.79177677, 0.76431068, 0.73791248,
0.71250742, 0.68805224, 0.66453346, 0.64196021, 0.62035121,
0.59971506, 0.5800232 , 0.56117499, 0.54295419, 0.52497612,
0.50662498, 0.48698059, 0.4647339 , 0.43809065, 0.40466247],
[1.475 , 1.4242308 , 1.37394048, 1.32472956, 1.27705866,
1.23125911, 1.18754636, 1.1460356 , 1.10675879, 1.06968242,
1.03472529, 1.00177563, 0.9707067 , 0.94139043, 0.91370806,
0.88755732, 0.86285533, 0.83953655, 0.81754494, 0.79681986,
0.77727473, 0.75876792, 0.74106511, 0.72379234, 0.70637915,
0.687991 , 0.66745028, 0.64314527, 0.61292625, 0.57398802],
[1.7125 , 1.65578431, 1.59937362, 1.54401386, 1.49029576,
1.43866495, 1.38943515, 1.34280386, 1.29886974, 1.25765082,
1.21910288, 1.18313715, 1.14963664, 1.11847019, 1.08950364,
1.06260722, 1.03765842, 1.01453964, 0.99312968, 0.97328851,
0.95483439, 0.93751264, 0.92095522, 0.90463049, 0.88778219,
0.86935702, 0.84791997, 0.82155665, 0.78776186, 0.74331358],
[1.95 , 1.88733782, 1.82480676, 1.76329816, 1.70353287,
1.6460708 , 1.59132394, 1.53957212, 1.49098069, 1.44561922,
1.40348046, 1.36449867, 1.32856657, 1.29554994, 1.26529921,
1.23765712, 1.21246152, 1.18954273, 1.16871442, 1.14975716,
1.13239406, 1.11625736, 1.10084533, 1.08546864, 1.06918523,
1.05072304, 1.02838966, 0.99996803, 0.96259746, 0.91263913]])}, 'samples': {'t': array([0. , 0.03275862, 0.06551724, 0.09827586, 0.13103448,
0.1637931 , 0.19655172, 0.22931034, 0.26206897, 0.29482759,
0.32758621, 0.36034483, 0.39310345, 0.42586207, 0.45862069,
0.49137931, 0.52413793, 0.55689655, 0.58965517, 0.62241379,
0.65517241, 0.68793103, 0.72068966, 0.75344828, 0.7862069 ,
0.81896552, 0.85172414, 0.88448276, 0.91724138, 0.95 ]), 'x': array([0. , 0.2375, 0.475 , 0.7125, 0.95 ])}}
Schritt 2 (falls erforderlich): Problem für de Ausführung auf Quantenhardware optimiern
Standardmäßig verwendet da Solver physikalisch informierte Parameter, des san initiale Schaltungsparameter für a gegebene Qubit-Anzahl und -Tiefe, vun wo unser Solver ausgeht.
De Shots san au Teil vun de Parameter mit am Standardwert, da deren Feinabstimmung wichtig is.
Je nach da Konfiguration, de mia z'lösen versuchen, müssen de Parameter vum Algorithmus vielleicht angepasst wern, um zufriedenstellende Lösungen z'erzieln; zum Beispiel kann es mehr oder weniger Qubits pro Variable und erfordern, je nach und . Des Folgende passt de Anzahl vun de Qubits pro Funktion pro Variable, de Tiefe pro Funktion und de Anzahl vun de Shots an.
Mia kenna au schaugn, wie mia des Backend und da Ausführungsmodus spezifizieren.
Darüber hinaus kenna physikalisch informierte Parameter da Optimierungsprozess
in de falsche Richtung lenken; in dem Fall kenna mia des deaktivieren, indem mia de
initialization-Strategie auf "RANDOM" setzn.
job_2 = quick.run(
use_case="cfd",
physical_parameters={"a": 0.5, "b": 0.25},
nb_qubits={"u": {"t": 2, "x": 1}},
depth={"u": 3},
shots=[500, 2500, 5000, 10000],
initialization="RANDOM",
backend="ibm_kingston",
mode="session",
)
print(job_2.result())
{'functions': {'u': array([[0.25 , 0.24856543, 0.24687708, 0.2449444 , 0.24277686,
0.24038389, 0.23777496, 0.23495952, 0.23194702, 0.22874691,
0.22536866, 0.22182171, 0.21811551, 0.21425952, 0.2102632 ,
0.20613599, 0.20188736, 0.19752675, 0.19306361, 0.18850741,
0.18386759, 0.1791536 , 0.17437491, 0.16954096, 0.16466122,
0.15974512, 0.15480213, 0.1498417 , 0.14487328, 0.13990632],
[0.36875 , 0.36681313, 0.36457201, 0.36203594, 0.35921422,
0.35611615, 0.35275103, 0.34912817, 0.34525687, 0.34114643,
0.33680614, 0.33224532, 0.32747327, 0.32249928, 0.31733266,
0.31198271, 0.30645873, 0.30077002, 0.29492589, 0.28893564,
0.28280857, 0.27655397, 0.27018116, 0.26369944, 0.2571181 ,
0.25044645, 0.24369378, 0.23686941, 0.22998264, 0.22304275],
[0.4875 , 0.48506084, 0.48226695, 0.47912748, 0.47565158,
0.47184841, 0.46772711, 0.46329683, 0.45856672, 0.45354594,
0.44824363, 0.44266894, 0.43683103, 0.43073904, 0.42440212,
0.41782942, 0.4110301 , 0.4040133 , 0.39678818, 0.38936388,
0.38174955, 0.37395435, 0.36598742, 0.35785791, 0.34957498,
0.34114777, 0.33258544, 0.32389713, 0.315092 , 0.30617919],
[0.60625 , 0.60330854, 0.59996188, 0.59621902, 0.59208895,
0.58758067, 0.58270318, 0.57746549, 0.57187658, 0.56594545,
0.55968112, 0.55309256, 0.54618879, 0.53897879, 0.53147158,
0.52367614, 0.51560147, 0.50725658, 0.49865046, 0.48979211,
0.48069053, 0.47135472, 0.46179367, 0.45201638, 0.44203186,
0.4318491 , 0.42147709, 0.41092485, 0.40020136, 0.38931562],
[0.725 , 0.72155625, 0.71765682, 0.71331056, 0.70852631,
0.70331293, 0.69767926, 0.69163414, 0.68518643, 0.67834497,
0.6711186 , 0.66351618, 0.65554655, 0.64721855, 0.63854104,
0.62952285, 0.62017284, 0.61049986, 0.60051274, 0.59022035,
0.57963151, 0.56875509, 0.55759992, 0.54617486, 0.53448874,
0.52255042, 0.51036875, 0.49795257, 0.48531072, 0.47245205]])}, 'samples': {'t': array([0. , 0.03275862, 0.06551724, 0.09827586, 0.13103448,
0.1637931 , 0.19655172, 0.22931034, 0.26206897, 0.29482759,
0.32758621, 0.36034483, 0.39310345, 0.42586207, 0.45862069,
0.49137931, 0.52413793, 0.55689655, 0.58965517, 0.62241379,
0.65517241, 0.68793103, 0.72068966, 0.75344828, 0.7862069 ,
0.81896552, 0.85172414, 0.88448276, 0.91724138, 0.95 ]), 'x': array([0. , 0.2375, 0.475 , 0.7125, 0.95 ])}}
Schritt 3: Vergleich vun de Algorithmusleistungen
Mia kenna da Konvergenzprozess vun unserer Lösung (HDES) vun job_2 mit da Leistung vun am Physics-Informed Neural Networks (PINN)-Algorithmus und -Solver vergleichen (schaugts des Paper und des zugehörige GitHub-Repository).
Im Beispiel vun da Ausgabe vun job_2 (quantenbasierter Ansatz) wern nur 13 Parameter (12 Schaltungsparameter plus 1 Skalierungsparameter) mit dem klassischen Solver optimiert. Da Konvergenzprozess verläuft so:
optimizers:
CMA: {'ftarget': np.float64(0.1), 'verb_disp': 10, 'maxiter': 100}
CMA: {'ftarget': np.float64(0.005), 'verb_disp': 10, 'maxiter': 20}
CMA: {'ftarget': np.float64(0.0025), 'verb_disp': 10, 'maxiter': 30}
CMA: {'ftarget': np.float64(0.0005), 'verb_disp': 10, 'maxiter': 10}
500 shots
================== CMA =================
option: {'ftarget': np.float64(0.1), 'verb_disp': 10, 'maxiter': 100}
0/100, loss: 0.02456641
1000 shots
================== CMA =================
option: {'ftarget': np.float64(0.005), 'verb_disp': 10, 'maxiter': 20}
0/20, loss: 0.03641833
1/20, loss: 0.02461719
2/20, loss: 0.0283689
3/20, loss: 0.009898383
4/20, loss: 0.04454522
5/20, loss: 0.007019971
6/20, loss: 0.00811147
7/20, loss: 0.01592619
8/20, loss: 0.00764708
9/20, loss: 0.01401516
10/20, loss: 0.01767467
11/20, loss: 0.01220387
5000 shots
================== CMA =================
option: {'ftarget': np.float64(0.0025), 'verb_disp': 10, 'maxiter': 30}
0/30, loss: 0.01024792
1/30, loss: 0.004343748
2/30, loss: 0.01450951
3/30, loss: 0.008591284
4/30, loss: 0.00266414
5/30, loss: 0.007923613
6/30, loss: 0.02023853
7/30, loss: 0.01031438
8/30, loss: 0.009513116
9/30, loss: 0.008132266
10/30, loss: 0.005787766
11/30, loss: 0.00390582
10000 shots
================== CMA =================
option: {'ftarget': np.float64(0.0005), 'verb_disp': 10, 'maxiter': 10}
0/10, loss: 0.002386168
1/10, loss: 0.004024823
2/10, loss: 0.001311999
3/10, loss: 0.003433991
4/10, loss: 0.002339664
5/10, loss: 0.002978438
6/10, loss: 0.005458391
7/10, loss: 0.002026701
8/10, loss: 0.00207467
9/10, loss: 0.001947627
final_loss: 0.00151994463476429
Des bedeutet, dass a Loss unter 0,0015 nach 28 Iterationen erreicht wern kann, und des bei da Optimierung vun nur wenigen klassischen Parametern.
Jetzt kenna mia dasselbe mit da PINN-Lösung mit da vum Paper vorgeschlagenen Standardkonfiguration unter Verwendung vun am gradientenbasierten Optimierer vergleichen. Des Äquivalent vun unserer Schaltung mit 13 z'optimierenden Parametern is des neuronale Netzwerk, des mindestens acht Schichten mit 20 Neuronen braucht und somit de Optimierung vun 3021 Parametern beinhaltet. Dann wird da Ziel-Loss bei Schritt 315, Loss: 0,0014988397, erreicht.

Jetzt, wo mia an fairen Vergleich machen möchten, sollt mia in beiden Fälln denselben Optimierer verwenden. De niedrigste Anzahl vun Iterationen, de mia für 12 Schichten mit 20 Neuronen = 4701 Parameter gfunden ham:
(10_w,20)-aCMA-ES (mu_w=5.9,w_1=27%) in dimension 4701 (seed=351961)
Iterat #Fevals function value axis ratio sigma min&max std t[m:s]
1 20 5.398521572351456e-02 1.0e+00 9.98e-03 1e-02 1e-02 0:02.3
2 40 5.444650724530220e-02 1.0e+00 9.97e-03 1e-02 1e-02 0:05.1
3 60 4.447407275438309e-02 1.0e+00 9.95e-03 1e-02 1e-02 0:08.2
4 80 2.068969979882240e-02 1.0e+00 9.94e-03 1e-02 1e-02 0:11.7
6 120 1.028892211616039e-02 1.0e+00 9.91e-03 1e-02 1e-02 0:20.1
7 140 5.140972323715687e-03 1.0e+00 9.90e-03 1e-02 1e-02 0:25.4
9 180 3.811701666563749e-03 1.0e+00 9.87e-03 1e-02 1e-02 0:37.4
10 200 3.189878538250923e-03 1.0e+00 9.85e-03 1e-02 1e-02 0:44.2
12 240 2.547040116041899e-03 1.0e+00 9.83e-03 1e-02 1e-02 0:59.7
14 280 2.166548743844032e-03 1.0e+00 9.80e-03 1e-02 1e-02 1:18.0
15 300 1.783065614290535e-03 1.0e+00 9.79e-03 1e-02 1e-02 1:28.4
16 320 2.045844215899706e-03 1.0e+00 9.78e-03 1e-02 1e-02 1:39.8
Stopping early: loss 0.001405 <= target 0.0015
CMA-ES finished. Best loss: 0.001404788694344461
Mia kenna dasselbe mit unsern Daten vun job_2 machn und an Vergleich mit da PINN-Lösung darstellen.
# check the loss function and compare between the two approaches
print(job_2.logs())
Schritt 4: Verwendung vum Ergebnis
Mit unserer Lösung kenna mia jetzt wählen, was mia damit machn möchten. Des Folgende zeigt, wie mia des Ergebnis darstellen.
solution = job.result()
# Plot the solution of the second simulation job_2
_ = plt.figure()
ax = plt.axes(projection="3d")
# plot the solution using the 3d plotting capabilities of pyplot
t, x = np.meshgrid(solution["samples"]["t"], solution["samples"]["x"])
ax.plot_surface(
t,
x,
solution["functions"]["u"],
edgecolor="royalblue",
lw=0.25,
rstride=26,
cstride=26,
alpha=0.3,
)
ax.scatter(t, x, solution, marker=".")
ax.set(xlabel="t", ylabel="x", zlabel="u(t,x)")
plt.show()

Beachts da Unterschied vun da Anfangsbedingung für da zweiten Durchlauf und seine Auswirkung auf des Ergebnis:
solution_2 = job_2.result()
# Plot the solution of the second simulation job_2
_ = plt.figure()
ax = plt.axes(projection="3d")
# plot the solution using the 3d plotting capabilities of pyplot
t, x = np.meshgrid(solution_2["samples"]["t"], solution_2["samples"]["x"])
ax.plot_surface(
t,
x,
solution_2["functions"]["u"],
edgecolor="royalblue",
lw=0.25,
rstride=26,
cstride=26,
alpha=0.3,
)
ax.scatter(t, x, solution_2, marker=".")
ax.set(xlabel="t", ylabel="x", zlabel="u(t,x)")
plt.show()

Tutorial-Umfrage
Nehmt's eich bitte a Minute Zeit, um Feedback zu diesem Tutorial z'geben. Eure Erkenntnisse helfn uns, unser Inhaltsangebot und unsere Benutzererfahrung z'verbessern: