diff --git a/src/data/content.json b/src/data/content.json
new file mode 100644
index 0000000..c00bd20
--- /dev/null
+++ b/src/data/content.json
@@ -0,0 +1,64 @@
+{
+ "tunneling": [
+ {
+ "title": "What is tunneling?",
+ "imageUrl": "https://www.wikihow.com/images/thumb/3/32/Play-Wall-Ball-Step-9-Version-2.jpg/v4-460px-Play-Wall-Ball-Step-9-Version-2.jpg.webp",
+ "msg": "Imagine you're hitting a ball at a wall. Normally, the ball would just bounce back, right? But in quantum physics, sometimes the ball can go through the wall, even if the wall is solid! This is a concept called tunneling."
+ },
+ {
+ "title": "Why do particles act so strange?",
+ "msg": "Particles, like tiny pieces of matter, don't always act the way we expect them to. In regular physics, like with balls or cars, we can predict where things will go. But in quantum physics, these tiny particles are super unpredictable! Their position is a bit fuzzy, and sometimes they show up where you'd never expect them to. This is why they can tunnel through barriers."
+ },
+ {
+ "title": "What affects whether the ball goes through the wall?",
+ "msg": "There are a few things that make tunneling easier for particles:\n- If the wall (or barrier) is thinner.\n- If the wall is weaker (lower energy).\n- If the particle is moving faster (has more energy).\nWhen these things happen, the particle (or tennis ball) is more likely to go through the wall!"
+ },
+ {
+ "title": "Try it out!",
+ "msg": "Change the thickness and strength of the barrier, and adjust the energy of the particle. Does the particle always tunnel through? What does the pattern of the particle's behavior look like when it reaches the barrier? How does it change as the particle moves? See what happens!"
+ }
+ ],
+ "interference": [
+ {
+ "title": "What is interference?",
+ "imageUrl": "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzBWFVf3m3-Wh1k4q9mNAxbDcDTS_4qEiZ7SK_dG2iQO9dUP6r4IAq8eXiK0utCTeafofhwb8gvWpt8J8oTziDUq3EnoTYbpvLASi8gnrW3E5k59PnSDh48JGNiY5sjj_l9BjOGiOqgY-d/?imgmax=800",
+ "msg": "In quantum physics, tiny particles can be in more than one place at once! This idea is called \"superposition.\" Not only that, but sometimes these particles, like light particles (called photons), can actually interfere with themselves, just like two waves crossing each other in water!"
+ },
+ {
+ "title": "Are quantum particles waves?",
+ "msg": "Particles in quantum physics don't act like everyday objects. These tiny particles, like electrons or photons, act like both **particles** (solid objects) and **waves** (like water waves). This special behavior is called **wave-particle duality**. Scientists use something called the **DeBroglie wavelength** to figure out how wavy a particle is. The smaller the particle's energy, the more like a wave it behaves!"
+ },
+ {
+ "title": "How is wavelength calculated?",
+ "msg": "Scientists use a formula to find out how wavy a particle is. It looks like this: \n$$ F = p/h $$ \nBut what does that mean? It means that if a particle is moving really fast (high momentum), its wavelength becomes super tiny! But for small particles, like electrons or photons, the waves are bigger and easier to see."
+ },
+ {
+ "title": "The Double Slot Experiment",
+ "imageUrl": "https://quantumawareness.net/wp-content/uploads/2019/01/doubleslottest-1400x793-71-2.jpg",
+ "msg": "Here’s a cool experiment that shows how photons (light particles) act like both particles and waves. You’d think you’d see two lines on the other side, right? But what you actually see is a pattern of light and dark lines, like waves crossing in water! \n\nThis is because the photons aren’t just acting like particles. They’re also behaving like waves that **interfere** with each other, creating this special pattern."
+ },
+ {
+ "title": "Try it out!",
+ "msg": "Change the distance between the slits, or change how much energy the wave has. \n- What happens to the pattern on the wall? \n- Does the wave’s energy change the spacing of the light and dark lines? \n\nTry it out and see how waves and particles are both part of the same strange quantum world!"
+ }
+ ],
+ "spin": [
+ {
+ "title": "What is qubit and a \"spin\"?",
+ "msg": "In quantum computers, we use something called qubits to store information. Unlike regular computer bits (which are either 0 or 1), qubits can be a mix of both at the same time! One way we can control a qubit is by using the **spin** of a tiny particle, like an electron. Imagine the electron spinning like a top—this spin helps us control how the qubit behaves."
+ },
+ {
+ "title": "How does spin change?",
+ "msg": "To control the spin of a particle, we apply a **magnetic field**. This makes the particle spin around in a circle! We measure how much it spins and use that to decide how well our quantum computer is working. The goal is to rotate the spin by just the right amount, which we call a **quantum gate**."
+ },
+ {
+ "title": "The Bloch Sphere",
+ "imagePath": "/Single_V4.png",
+ "msg": "We can picture the spin of an electron using a model called the **Bloch sphere**. It’s like a globe, and the spin is a point on the surface of the globe that moves around as the magnetic field changes. By looking at the Bloch sphere, we can see exactly how the spin is moving!"
+ },
+ {
+ "title": "Try it out!",
+ "msg": "Now it’s your turn to explore! In this experiment, you can adjust the magnetic field and see how it affects the spin of a qubit. Watch how the qubit’s spin changes on the Bloch sphere. Can you find the right amount of spin for the quantum gate?"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/pages/Interference.tsx b/src/pages/Interference.tsx
index dd530ae..7d3ba9a 100644
--- a/src/pages/Interference.tsx
+++ b/src/pages/Interference.tsx
@@ -170,36 +170,7 @@ const Interference = () => {
-
-
-
-
-
+
{
- {/**/}
-
-
-
-
+
{
- {/**/}
-
-
-
-
+
Date: Wed, 20 Nov 2024 13:22:42 -0500
Subject: [PATCH 05/13] Cleaning and restructuring Tunneling and Interference,
and editing custom component to show the name of the model it is generating
---
src/components/CustomTitle.tsx | 4 +-
src/pages/Interference.tsx | 224 +++++++++++++++----------
src/pages/Tunneling.tsx | 297 ++++++++++++++++++---------------
3 files changed, 300 insertions(+), 225 deletions(-)
diff --git a/src/components/CustomTitle.tsx b/src/components/CustomTitle.tsx
index 49717de..c0ebbcd 100644
--- a/src/components/CustomTitle.tsx
+++ b/src/components/CustomTitle.tsx
@@ -12,7 +12,7 @@ const card_style = {
// ==========================================
// ============== CustomTitle ==============
// ==========================================
-const CustomTitle = () => {
+const CustomTitle = ({pageName = "Quantum"}) => {
return (
@@ -26,7 +26,7 @@ const CustomTitle = () => {
margin: 0,
}}
>
- Quantum Model Generator
+ {pageName} Model Generator
diff --git a/src/pages/Interference.tsx b/src/pages/Interference.tsx
index 7d3ba9a..022a2b5 100644
--- a/src/pages/Interference.tsx
+++ b/src/pages/Interference.tsx
@@ -167,99 +167,139 @@ const Interference = () => {
}
return (
-
-
-
-
-
-
- :not(style)": { m: 0.5, width: "25ch" },
- }}
- noValidate
- autoComplete="off"
- display="flex"
- flexDirection="column"
- >
-
-
-
- Spacing
-
-
-
- Slit Separation
-
-
-
- Wave
-
-
- {loading ? (
-
- ) : (
-
- )}
-
-
-
+
-
-
-
-
-
+
+
+ {/* Title for the page */}
+
+
+ {/* Content for the page imported from data.json */}
+
+
+
+
+
+
+ :not(style)": { width: "200px" },
+ border: "1px solid ",
+ }}
+ noValidate
+ autoComplete="off"
+ display="flex"
+ flexDirection="column" >
+
+
+
+
+
+
+
+ Spacing
+
+
+
+
+
+
+ Slit Separation
+
+
+
+
+
+
+ Wave
+
+
+
+
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
);
};
diff --git a/src/pages/Tunneling.tsx b/src/pages/Tunneling.tsx
index 249e48c..1539142 100644
--- a/src/pages/Tunneling.tsx
+++ b/src/pages/Tunneling.tsx
@@ -181,137 +181,172 @@ const Tunneling = () => {
// ========= return =========
return (
-
-
-
-
-
-
-
-
-
- :not(style)": { m: 0.5, width: "25ch" },
- }}
- noValidate
- autoComplete="off"
- style={horizontal_center}
- >
-
-
-
-
- Barrier
-
-
-
- (eV)
-
-
-
- {/* ====== Thickness Slider ====== */}
-
-
- Thickness
-
-
-
- (nm)
-
-
-
- {/* ====== Wave Select ====== */}
-
-
- Wave number k
-
-
-
- (nm)
- -1
-
-
-
- {/* ====== Submit Button ====== */}
- {loading ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {/* Title for the page */}
+
+
+ {/* Content for the page imported from data.json */}
+
+
+
+
+
+
+ :not(style)": { m: 0.5, width: "25ch" },
+ }}
+ noValidate
+ autoComplete="off"
+ style={horizontal_center} >
+
+
+
+
+
+
+
+ Barrier
+
+
+
+ (eV)
+
+
+
+ {/* ====== Thickness Slider ====== */}
+
+
+ Thickness
+
+
+
+ (nm)
+
+
+
+ {/* ====== Wave Select ====== */}
+
+
+ Wave number k
+
+
+
+ (nm)
+ -1
+
+
+
+ {/* ====== Submit Button ====== */}
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
From 4f9262de395c43c5c084a6477e810ad3bf044ccd Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 20 Nov 2024 13:41:48 -0500
Subject: [PATCH 06/13] mongodb setup, operation failing
---
quantum_app_backend/app.py | 54 ++++++++++++++--------------
quantum_app_backend/db.py | 39 ++++++++++++++++++++
quantum_app_backend/requirements.txt | 3 +-
3 files changed, 69 insertions(+), 27 deletions(-)
create mode 100644 quantum_app_backend/db.py
diff --git a/quantum_app_backend/app.py b/quantum_app_backend/app.py
index bc1042c..6a6bf90 100755
--- a/quantum_app_backend/app.py
+++ b/quantum_app_backend/app.py
@@ -10,6 +10,7 @@
import os
from pathlib import Path
import portalocker
+from db import add_tunneling, get_tunneling
#set swagger info
api: Api = Api(
@@ -20,9 +21,7 @@
)
app = Flask(__name__)
-
api.init_app(app)
-
CORS(app, resources={r"/*": {"origins": "*"}})
@app.route('/receive_data/tunneling/
//', methods=['GET'])
@@ -31,27 +30,35 @@ def Qtunneling(barrier, width, momentum):
width = float(width)
momentum = float(momentum)
- print("You evoked the API successfully")
- if Path(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html').exists():
- print(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html')
- with open(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html',
- "r") as f:
- portalocker.lock(f, portalocker.LOCK_SH)
- GifRes = f.read()
+ print("You evoked the tunneling API successfully")
+ # Get tunneling models based on barrier, width, and momentum
+ tunneling_model = get_tunneling(barrier, width, momentum)
+ if tunneling_model:
+ print('Tunneling model found')
+ return {'GifRes': tunneling_model['frames']}
else:
- plt.close('all')
- plt.switch_backend('Agg')
+ return {'tunneling_model': 'No tunneling model found'}
+
+ # if Path(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html').exists():
+ # print(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html')
+ # with open(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html',
+ # "r") as f:
+ # portalocker.lock(f, portalocker.LOCK_SH)
+ # GifRes = f.read()
+ # else:
+ # plt.close('all')
+ # plt.switch_backend('Agg')
- start_3d_time = time.time() # Record the start time
- wave_packet3D = t_wp(barrier_width=width, barrier_height=barrier, k0=momentum)
- animator = t_ani(wave_packet3D)
- GifRes = animator.animate3D()
+ # start_3d_time = time.time() # Record the start time
+ # wave_packet3D = t_wp(barrier_width=width, barrier_height=barrier, k0=momentum)
+ # animator = t_ani(wave_packet3D)
+ # GifRes = animator.animate3D()
- end_3d_time = time.time() # Record the end time
- elapsed_3d_time = end_3d_time - start_3d_time
- print(f"Elapsed 3D generator time: {elapsed_3d_time} seconds")
+ # end_3d_time = time.time() # Record the end time
+ # elapsed_3d_time = end_3d_time - start_3d_time
+ # print(f"Elapsed 3D generator time: {elapsed_3d_time} seconds")
- return {'GifRes': GifRes}
+ # return {'GifRes': GifRes}
@app.route('/receive_data/interference///', methods=['GET'])
@@ -101,15 +108,10 @@ def Qtrace(gate, init_state, mag, t2):
return {'GifRes': GifRes}
-
-@app.route('/hello', methods=['GET', 'POST'])
-def welcome():
- return "Hello World!"
-
-
#blind namespace to swagger api page
if __name__ == '__main__':
app.debug = True
+ app.config['MONGO_URI'] = 'mongodb+srv://ufquantumcomputing:ufquantumcomputing@cluster0.4ulpp.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0'
- #run backend server at port 5001
+ #run backend server at port 3001
app.run(host="0.0.0.0", port=3001, threaded=False, debug=True)
\ No newline at end of file
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
new file mode 100644
index 0000000..94f5293
--- /dev/null
+++ b/quantum_app_backend/db.py
@@ -0,0 +1,39 @@
+import bson
+
+from flask import app
+from werkzeug.local import LocalProxy
+import pymongo
+import gridfs
+from pymongo.errors import DuplicateKeyError, OperationFailure
+from bson.objectid import ObjectId
+from bson.errors import InvalidId
+import os
+from mongo_connection import MONGO_URI
+
+# Create a gridfs instance from a mongodb instance
+client = pymongo.MongoClient(MONGO_URI)
+db = client['models']
+fs = gridfs.GridFS(db)
+
+def add_tunneling():
+ # Write files from /cache/tunneling to MongoDB using GridFS
+ try:
+ # Write all tunneling models from ./cache/tunneling to MongoDB using GridFS
+ for file in os.listdir('cache/tunneling'):
+ with open(f'cache/tunneling/{file}', 'rb') as f:
+ print('Adding tunneling models from cache file')
+ fs.put(f, filename=file)
+ except Exception as e:
+ return e
+
+def get_tunneling(barrier, width, momentum):
+ # Read tunneling models from MongoDB using GridFS
+ barrier = float(barrier)
+ width = float(width)
+ momentum = float(momentum)
+
+ try:
+ print('Getting tunneling model')
+ return fs.get(ObjectId('6734f0c4cd8c9ba1c6f54b7c'))
+ except pymongo.errors.OperationFailure:
+ print('Operation Failure')
\ No newline at end of file
diff --git a/quantum_app_backend/requirements.txt b/quantum_app_backend/requirements.txt
index 6c2c563..74d5404 100644
--- a/quantum_app_backend/requirements.txt
+++ b/quantum_app_backend/requirements.txt
@@ -23,4 +23,5 @@ zipp>=3.15.0
ipython>=8.17.2
odeintw
portalocker
-matplotlib
\ No newline at end of file
+matplotlib
+flask-pymongo
\ No newline at end of file
From 3d57046cc54b29977d30b19b6022d19f61f4b46a Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 20 Nov 2024 13:56:44 -0500
Subject: [PATCH 07/13] mongo atlas connection working
---
quantum_app_backend/db.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
index 94f5293..f8568af 100644
--- a/quantum_app_backend/db.py
+++ b/quantum_app_backend/db.py
@@ -33,7 +33,12 @@ def get_tunneling(barrier, width, momentum):
momentum = float(momentum)
try:
- print('Getting tunneling model')
- return fs.get(ObjectId('6734f0c4cd8c9ba1c6f54b7c'))
- except pymongo.errors.OperationFailure:
- print('Operation Failure')
\ No newline at end of file
+ collection = db['tunneling']
+ tunneling_model = collection.find_one({'barrier': 1, 'thickness': 1, 'wave': 1})
+ if tunneling_model:
+ return tunneling_model
+ else:
+ return None
+ except pymongo.errors.OperationFailure as e:
+ print(e.details)
+ return None
\ No newline at end of file
From b3ffc0d2b8a5d598540d1adb452e97ee51d6628e Mon Sep 17 00:00:00 2001
From: Raiden Williams
Date: Wed, 20 Nov 2024 13:56:54 -0500
Subject: [PATCH 08/13] Fixing code in SingleQgate page
---
src/pages/Interference.tsx | 2 +-
src/pages/SingleQgate.tsx | 316 ++++++++++++++++++++-----------------
2 files changed, 175 insertions(+), 143 deletions(-)
diff --git a/src/pages/Interference.tsx b/src/pages/Interference.tsx
index 022a2b5..2ad4883 100644
--- a/src/pages/Interference.tsx
+++ b/src/pages/Interference.tsx
@@ -166,7 +166,7 @@ const Interference = () => {
setOpenSnackbar(true); // open snackbar
}
- return (
+return (
{
setOpenSnackbar(true); // open snackbar
}
- return (
-
+return (
+
+
+
-
+ {/* Title for the page */}
+
+ {/* Content for the page imported from data.json */}
+
-
- :not(style)": { m: 0.5, width: "25ch" },
- }}
- noValidate
- autoComplete="off"
- display="flex"
- flexDirection="column"
- >
-
-
-
-
- Initial State
-
-
-
-
- {/* Init State Select */}
-
- {/**/}
- {/* Initial State*/}
- {/* */}
-
- Initial State
-
-
-
-
- {/* Mag slider */}
-
-
- Magnetic field
-
-
-
-
- {/* T2 slider */}
-
-
+
+
+
+ :not(style)": { m: 0.5, width: "25ch" },
+ }}
+ noValidate
+ autoComplete="off"
+ display="flex"
+ flexDirection="column">
+
+
+
+
+
+
+ Initial State
+
+
+
+
+
+
+ Initial State
+
+
+
+
+ {/* Mag slider */}
+
+
+ Magnetic field
+
+
+
+
+ {/* T2 slider */}
+
+
+ Dephasing time
+
+
+
+
+ {/* ====== Submit Button ====== */}
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
- Dephasing time
-
-
-
-
- {/* ====== Submit Button ====== */}
- {loading ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
- {/**/}
-
+
+
+
+
);
};
From 13f97b183d1dc2351f636b91a0c6c77721fe0c19 Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 20 Nov 2024 16:45:41 -0500
Subject: [PATCH 09/13] working readwrite using gridfs, need file checking
---
quantum_app_backend/app.py | 34 +---
quantum_app_backend/db.py | 56 +++----
src/pages/Tunneling.tsx | 308 ++++++++++++++++---------------------
3 files changed, 169 insertions(+), 229 deletions(-)
diff --git a/quantum_app_backend/app.py b/quantum_app_backend/app.py
index 6a6bf90..789a3e0 100755
--- a/quantum_app_backend/app.py
+++ b/quantum_app_backend/app.py
@@ -10,7 +10,8 @@
import os
from pathlib import Path
import portalocker
-from db import add_tunneling, get_tunneling
+from db import MongoGridFS
+from mongo_connection import MONGO_URI
#set swagger info
api: Api = Api(
@@ -32,33 +33,12 @@ def Qtunneling(barrier, width, momentum):
print("You evoked the tunneling API successfully")
# Get tunneling models based on barrier, width, and momentum
- tunneling_model = get_tunneling(barrier, width, momentum)
+ tunneling_model = gridfs.get_tunneling(barrier, width, momentum) # GridOut
if tunneling_model:
- print('Tunneling model found')
- return {'GifRes': tunneling_model['frames']}
+ print(tunneling_model.filename)
+ return tunneling_model.read()
else:
- return {'tunneling_model': 'No tunneling model found'}
-
- # if Path(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html').exists():
- # print(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html')
- # with open(f'cache/tunneling/probs_{momentum}_{barrier}_{width}_3D.html',
- # "r") as f:
- # portalocker.lock(f, portalocker.LOCK_SH)
- # GifRes = f.read()
- # else:
- # plt.close('all')
- # plt.switch_backend('Agg')
-
- # start_3d_time = time.time() # Record the start time
- # wave_packet3D = t_wp(barrier_width=width, barrier_height=barrier, k0=momentum)
- # animator = t_ani(wave_packet3D)
- # GifRes = animator.animate3D()
-
- # end_3d_time = time.time() # Record the end time
- # elapsed_3d_time = end_3d_time - start_3d_time
- # print(f"Elapsed 3D generator time: {elapsed_3d_time} seconds")
-
- # return {'GifRes': GifRes}
+ return None
@app.route('/receive_data/interference/
//', methods=['GET'])
@@ -111,7 +91,7 @@ def Qtrace(gate, init_state, mag, t2):
#blind namespace to swagger api page
if __name__ == '__main__':
app.debug = True
- app.config['MONGO_URI'] = 'mongodb+srv://ufquantumcomputing:ufquantumcomputing@cluster0.4ulpp.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0'
+ gridfs = MongoGridFS()
#run backend server at port 3001
app.run(host="0.0.0.0", port=3001, threaded=False, debug=True)
\ No newline at end of file
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
index f8568af..d17f095 100644
--- a/quantum_app_backend/db.py
+++ b/quantum_app_backend/db.py
@@ -11,34 +11,34 @@
from mongo_connection import MONGO_URI
# Create a gridfs instance from a mongodb instance
-client = pymongo.MongoClient(MONGO_URI)
-db = client['models']
-fs = gridfs.GridFS(db)
+class MongoGridFS:
+ def __init__(self):
+ self.client = pymongo.MongoClient(MONGO_URI)
+ self.db = self.client['models']
+ self.fs = gridfs.GridFS(self.db)
-def add_tunneling():
- # Write files from /cache/tunneling to MongoDB using GridFS
- try:
- # Write all tunneling models from ./cache/tunneling to MongoDB using GridFS
- for file in os.listdir('cache/tunneling'):
- with open(f'cache/tunneling/{file}', 'rb') as f:
- print('Adding tunneling models from cache file')
- fs.put(f, filename=file)
- except Exception as e:
- return e
+ if len(self.fs.list()) == 0:
+ self.add_tunneling()
-def get_tunneling(barrier, width, momentum):
- # Read tunneling models from MongoDB using GridFS
- barrier = float(barrier)
- width = float(width)
- momentum = float(momentum)
+ def add_tunneling(self):
+ # Write files from /cache/tunneling to MongoDB using GridFS
+ try:
+ # Write all tunneling models from ./cache/tunneling to MongoDB using GridFS
+ for file in os.listdir('cache/tunneling'):
+ with open(f'cache/tunneling/{file}', 'rb') as f:
+ print('Adding tunneling models from cache file')
+ self.fs.put(f, filename=file)
+ except Exception as e:
+ return e
- try:
- collection = db['tunneling']
- tunneling_model = collection.find_one({'barrier': 1, 'thickness': 1, 'wave': 1})
- if tunneling_model:
- return tunneling_model
- else:
- return None
- except pymongo.errors.OperationFailure as e:
- print(e.details)
- return None
\ No newline at end of file
+ def get_tunneling(self, barrier, width, momentum):
+ # Read tunneling models from MongoDB using GridFS
+ barrier = float(barrier)
+ width = float(width)
+ momentum = float(momentum)
+
+ try:
+ return self.fs.get_last_version(f'probs_{momentum}_{barrier}_{width}_3D.html')
+ except pymongo.errors.OperationFailure as e:
+ print(e.details)
+ return None
\ No newline at end of file
diff --git a/src/pages/Tunneling.tsx b/src/pages/Tunneling.tsx
index 1539142..55e4fc9 100644
--- a/src/pages/Tunneling.tsx
+++ b/src/pages/Tunneling.tsx
@@ -60,9 +60,8 @@ const Tunneling = () => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
- const responseData = await response.json();
- // console.log("responseData: ", responseData);
- setAnimationJsHtml(responseData.GifRes); // Adjust based on your API response structure
+ const responseData = await response.text();
+ setAnimationJsHtml(responseData); // Adjust based on your API response structure
return response.ok;
} catch (error) {
console.error("Error fetching animation from server:", error);
@@ -78,7 +77,6 @@ const Tunneling = () => {
.then((response) => response.text())
.then((text) => {
setAnimationJsHtml(text);
- console.log(text)
});
} catch (error) {
console.error('Failed to load default HTML content:', error);
@@ -88,7 +86,7 @@ const Tunneling = () => {
loadDefaultHtml();
}, []);
- // Your existing useEffect for handling animationJsHtml changes
+ // Existing useEffect for handling animationJsHtml changes
useEffect(() => {
if (animationJsHtml && animationContainerRef.current) {
const container = animationContainerRef.current;
@@ -136,9 +134,6 @@ const Tunneling = () => {
let barrier_str = barrier.toString();
let thickness_str = thickness.toString();
let wave_str = wave.toString();
- console.log("barrier:", barrier_str);
- console.log("thickness:", thickness_str);
- console.log("wave:", wave_str);
// if no input, set to default
if (barrier_str === "") {
@@ -181,172 +176,137 @@ const Tunneling = () => {
// ========= return =========
return (
-
-
-
-
- {/* Title for the page */}
-
-
- {/* Content for the page imported from data.json */}
-
-
-
-
-
-
- :not(style)": { m: 0.5, width: "25ch" },
- }}
- noValidate
- autoComplete="off"
- style={horizontal_center} >
-
-
-
-
-
-
-
- Barrier
-
-
-
- (eV)
-
-
-
- {/* ====== Thickness Slider ====== */}
-
-
- Thickness
-
-
-
- (nm)
-
-
-
- {/* ====== Wave Select ====== */}
-
-
- Wave number k
-
-
-
- (nm)
- -1
-
-
-
- {/* ====== Submit Button ====== */}
- {loading ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ :not(style)": { m: 0.5, width: "25ch" },
+ }}
+ noValidate
+ autoComplete="off"
+ style={horizontal_center}
+ >
+
+
+
+
+ Barrier
+
+
+
+ (eV)
+
+
+
+ {/* ====== Thickness Slider ====== */}
+
+
+ Thickness
+
+
+
+ (nm)
+
+
+
+ {/* ====== Wave Select ====== */}
+
+
+ Wave number k
+
+
+
+ (nm)
+ -1
+
+
+
+ {/* ====== Submit Button ====== */}
+ {loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
);
};
From 70431a6fec428453c9076647b390a91371d84e67 Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 20 Nov 2024 17:10:32 -0500
Subject: [PATCH 10/13] hide connection string, add instructions to readme
---
.gitignore | 6 +-----
README.md | 8 ++++++--
quantum_app_backend/app.py | 5 +----
quantum_app_backend/db.py | 12 +++++-------
quantum_app_backend/sample.ini | 2 ++
src/pages/Tunneling.tsx | 2 --
6 files changed, 15 insertions(+), 20 deletions(-)
create mode 100644 quantum_app_backend/sample.ini
diff --git a/.gitignore b/.gitignore
index d0fcb46..a53f508 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,12 +13,8 @@
/src/setup/
# misc
+.ini
.DS_Store
-.env
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
npm-debug.log*
yarn-debug.log*
diff --git a/README.md b/README.md
index 8761103..8407651 100644
--- a/README.md
+++ b/README.md
@@ -65,11 +65,15 @@ For example, I run the backend and I get "Running on http://127.0.0.1:3001". Tak
2. Utilize 2 terminals in parallel to run the back and the frontend.
-3. If you're cloning the project for the first time and changes to `/src/setup` are being tracked, run:
+3. Rename the `sample_ini` to `.ini` and replace the variable with the connection string from MongoDB Atlas.
```
-git update-index --assume-unchanged src/setup/
+mv sample_ini .ini
```
+[Get your Atlas cluster](https://docs.atlas.mongodb.com/getting-started/) with [sample data](https://docs.atlas.mongodb.com/sample-data/) set [connection string](https://docs.atlas.mongodb.com/connect-to-cluster/) and place in `DB_URI` parameter under `.ini`
+
+Make sure you have IP in the Atlas [access list](https://docs.atlas.mongodb.com/security/add-ip-address-to-list/) and username/password of your Atlas user correctly specified.
+
## File Structure
- `/src/` - Contains the source code for the React website.
- `/src/App.tsx` - The main entry point for the website. This is where the React Router is set up to route to the different pages.
diff --git a/quantum_app_backend/app.py b/quantum_app_backend/app.py
index 789a3e0..ecfc6c3 100755
--- a/quantum_app_backend/app.py
+++ b/quantum_app_backend/app.py
@@ -1,4 +1,4 @@
-from flask import Flask, jsonify, request
+from flask import Flask
from flask_restx import Api
from flask_cors import CORS
from model_generators.tunneling import Wave_Packet3D as t_wp, Animator3D as t_ani
@@ -6,12 +6,9 @@
from model_generators.Qgate1 import Qgate1
import matplotlib.pyplot as plt
import time
-import base64
-import os
from pathlib import Path
import portalocker
from db import MongoGridFS
-from mongo_connection import MONGO_URI
#set swagger info
api: Api = Api(
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
index d17f095..8e0c298 100644
--- a/quantum_app_backend/db.py
+++ b/quantum_app_backend/db.py
@@ -1,19 +1,17 @@
import bson
-
-from flask import app
-from werkzeug.local import LocalProxy
import pymongo
import gridfs
-from pymongo.errors import DuplicateKeyError, OperationFailure
-from bson.objectid import ObjectId
-from bson.errors import InvalidId
import os
+import configparser
from mongo_connection import MONGO_URI
+config = configparser.ConfigParser()
+config.read(os.path.abspath(os.path.join(".ini")))
+
# Create a gridfs instance from a mongodb instance
class MongoGridFS:
def __init__(self):
- self.client = pymongo.MongoClient(MONGO_URI)
+ self.client = pymongo.MongoClient(config['MONGO']['MONGO_URI'])
self.db = self.client['models']
self.fs = gridfs.GridFS(self.db)
diff --git a/quantum_app_backend/sample.ini b/quantum_app_backend/sample.ini
new file mode 100644
index 0000000..e63a6a5
--- /dev/null
+++ b/quantum_app_backend/sample.ini
@@ -0,0 +1,2 @@
+[MONGO]
+MONGO_URI = connection_string_here
\ No newline at end of file
diff --git a/src/pages/Tunneling.tsx b/src/pages/Tunneling.tsx
index 55e4fc9..5391799 100644
--- a/src/pages/Tunneling.tsx
+++ b/src/pages/Tunneling.tsx
@@ -42,8 +42,6 @@ const Tunneling = () => {
const [barrier, setBarrier] = useState(1);
const [thickness, setThickness] = useState(1.0);
const [wave, setWave] = useState(1);
- // const [tunneling_img2d_base64, set_Tunneling_img2d_base64] = useState(base64Text2d);
- // const [tunneling_img3d_base64, set_Tunneling_img3d_base64] = useState(base64Text3d);
const [animationJsHtml, setAnimationJsHtml] = useState('');
const animationContainerRef = useRef(null);
const [barrierSliderMoved, setBarrierSliderMoved] = useState(false);
From f985d3e1fe924578f3c24e7abd7ab2dc416539cd Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 20 Nov 2024 20:41:59 -0500
Subject: [PATCH 11/13] remove imports
---
quantum_app_backend/db.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
index 8e0c298..da76217 100644
--- a/quantum_app_backend/db.py
+++ b/quantum_app_backend/db.py
@@ -1,9 +1,7 @@
-import bson
import pymongo
import gridfs
import os
import configparser
-from mongo_connection import MONGO_URI
config = configparser.ConfigParser()
config.read(os.path.abspath(os.path.join(".ini")))
From 3ee6128b26b8829c23ed8f5522b41c30f865d41f Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 4 Dec 2024 15:46:07 -0500
Subject: [PATCH 12/13] gridFS configs and error handling
---
quantum_app_backend/app.py | 30 +++++---------------
quantum_app_backend/db.py | 57 ++++++++++++++++++++++++++++----------
src/pages/Interference.tsx | 51 ++++++++++++++++++++++++----------
src/pages/Tunneling.tsx | 46 ++++++++++++++++++++++--------
4 files changed, 120 insertions(+), 64 deletions(-)
diff --git a/quantum_app_backend/app.py b/quantum_app_backend/app.py
index ecfc6c3..fbbebda 100755
--- a/quantum_app_backend/app.py
+++ b/quantum_app_backend/app.py
@@ -1,3 +1,4 @@
+import flask
from flask import Flask
from flask_restx import Api
from flask_cors import CORS
@@ -32,10 +33,9 @@ def Qtunneling(barrier, width, momentum):
# Get tunneling models based on barrier, width, and momentum
tunneling_model = gridfs.get_tunneling(barrier, width, momentum) # GridOut
if tunneling_model:
- print(tunneling_model.filename)
return tunneling_model.read()
else:
- return None
+ flask.abort(400)
@app.route('/receive_data/interference///', methods=['GET'])
@@ -43,29 +43,13 @@ def Qinterference(spacing, slit_separation, momentum):
spacing = float(spacing)
slit_separation = float(slit_separation)
- print("You evoked the API successfully")
+ print("You evoked the interference API successfully")
- if Path(f'cache/interference/probs_{momentum}_{spacing}_{slit_separation}_3D.html').exists():
- print(f'cache/interference/probs_{momentum}_{spacing}_{slit_separation}_3D.html')
- with open(f'cache/interference/probs_{momentum}_{spacing}_{slit_separation}_3D.html',
- "r") as f:
- portalocker.lock(f, portalocker.LOCK_SH)
- GifRes = f.read()
+ interference_model = gridfs.get_interference(momentum, spacing, slit_separation)
+ if interference_model:
+ return interference_model.read()
else:
- plt.close('all')
- plt.switch_backend('Agg')
-
- start_3d_time = time.time()
- wave_packet3D = i_wp(slit_space=spacing, slit_sep=slit_separation, k0=momentum)
- animator3D = i_ani(wave_packet3D)
- GifRes = animator3D.animate3D()
-
- end_3d_time = time.time() # Record the end time
- elapsed_3d_time = end_3d_time - start_3d_time
- print(f"Elapsed 3D generator time: {elapsed_3d_time} seconds")
-
- return {'GifRes': GifRes}
-
+ flask.abort(400)
@app.route('/receive_data/evotrace////', methods=['GET'])
def Qtrace(gate, init_state, mag, t2):
diff --git a/quantum_app_backend/db.py b/quantum_app_backend/db.py
index da76217..2f9bfd6 100644
--- a/quantum_app_backend/db.py
+++ b/quantum_app_backend/db.py
@@ -11,30 +11,57 @@ class MongoGridFS:
def __init__(self):
self.client = pymongo.MongoClient(config['MONGO']['MONGO_URI'])
self.db = self.client['models']
- self.fs = gridfs.GridFS(self.db)
+ self.tunneling_fs = gridfs.GridFSBucket(self.db, bucket_name='tunneling')
+ self.interference_fs = gridfs.GridFSBucket(self.db, bucket_name='interference')
- if len(self.fs.list()) == 0:
- self.add_tunneling()
+ def get_tunneling(self, barrier, width, momentum):
+ # Read tunneling models from MongoDB using GridFS
+ try:
+ model = self.tunneling_fs.find({'filename':f'probs_{momentum}_{barrier}_{width}_3D.html'})
+ if model:
+ return model.sort('uploadDate', pymongo.DESCENDING).limit(1)[0]
+ except IndexError as e:
+ print(e)
+ return None
+
+ def get_interference(self, momentum, spacing, slit_separation):
+ # Read interference models from MongoDB using GridFS
+ try:
+ model = self.interference_fs.find({'filename':f'probs_{momentum}_{spacing}_{slit_separation}_3D.html'})
+ if model:
+ return model.sort('uploadDate', pymongo.DESCENDING).limit(1)[0]
+ except IndexError as e:
+ print(e)
+ return None
- def add_tunneling(self):
+def add_tunneling(db):
# Write files from /cache/tunneling to MongoDB using GridFS
+ bucket = gridfs.GridFSBucket(db, bucket_name='tunneling')
try:
# Write all tunneling models from ./cache/tunneling to MongoDB using GridFS
for file in os.listdir('cache/tunneling'):
with open(f'cache/tunneling/{file}', 'rb') as f:
print('Adding tunneling models from cache file')
- self.fs.put(f, filename=file)
- except Exception as e:
+ bucket.upload_from_stream(file, f)
+ except ValueError as e:
return e
- def get_tunneling(self, barrier, width, momentum):
- # Read tunneling models from MongoDB using GridFS
- barrier = float(barrier)
- width = float(width)
- momentum = float(momentum)
+def add_interference(db):
+ # Write files from /cache/interference to MongoDB using GridFS
+ bucket = gridfs.GridFSBucket(db, bucket_name='interference')
try:
- return self.fs.get_last_version(f'probs_{momentum}_{barrier}_{width}_3D.html')
- except pymongo.errors.OperationFailure as e:
- print(e.details)
- return None
\ No newline at end of file
+ # Write all tunneling models from ./cache/interference to MongoDB using GridFS
+ for file in os.listdir('cache/interference'):
+ with open(f'cache/interference/{file}', 'rb') as f:
+ print('Adding interference models from cache file')
+ bucket.upload_from_stream(file, f)
+ except ValueError as e:
+ return e
+
+# Driver to write cache files to MongoDB
+if __name__ == '__main__':
+ client = pymongo.MongoClient(config['MONGO']['MONGO_URI'])
+ db = client['models']
+ add_tunneling(db)
+ add_interference(db)
\ No newline at end of file
diff --git a/src/pages/Interference.tsx b/src/pages/Interference.tsx
index 2ad4883..f22fcfd 100644
--- a/src/pages/Interference.tsx
+++ b/src/pages/Interference.tsx
@@ -12,7 +12,8 @@ import {
FormControl,
Slider,
Card,
- CardContent
+ CardContent,
+ AlertProps,
} from "@mui/material";
import CircularProgress from '@mui/joy/CircularProgress';
import { Layout } from "antd";
@@ -48,21 +49,21 @@ const Interference = () => {
const [spacingSliderMoved, setSpacingSliderMoved] = useState(false);
const [slitSepSliderMoved, setSlitSepSliderMoved] = useState(false);
const [waveSliderMoved, setWaveSliderMoved] = useState(false);
- const [success_msg, set_Success_Msg] = useState(
- "Interference model generated with spacing = " + spacing.toString() + ", slitSep = " + slit_separation.toString() + ", and wave = " + momentum.toString() + "!"
- );
- const [open, setOpenSnackbar] = useState(false);
+ const [snackbarMsg, setSnackbarMessage] = useState("Default interference model generated!");
+ const [severity, setSeverity] = useState('success');
+ const [openSnackBar, setOpenSnackbar] = useState(false);
// ========= handle functions =========
async function getGifFromServer(request_url: string) {
try {
const response = await fetch(request_url, {method: 'GET'});
if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
+ console.error("Error fetching animation from server");
+ setSeverity('error');
+ return null;
}
- const responseData = await response.json();
- // console.log("responseData: ", responseData);
- setAnimationJsHtml(responseData.GifRes); // Adjust based on your API response structure
+ const responseData = await response.text();
+ setAnimationJsHtml(responseData); // Adjust based on your API response structure
return response.ok;
} catch (error) {
console.error("Error fetching animation from server:", error);
@@ -81,11 +82,13 @@ const Interference = () => {
});
} catch (error) {
console.error('Failed to load default HTML content:', error);
+ setSeverity('error');
}
};
loadDefaultHtml();
}, []);
+
useEffect(() => {
if (animationJsHtml && animationContainerRef.current) {
const container = animationContainerRef.current;
@@ -103,6 +106,12 @@ const Interference = () => {
}
}, [animationJsHtml]);
+ useEffect(() => {
+ if (snackbarMsg) {
+ setOpenSnackbar(true);
+ }
+ }, [snackbarMsg]);
+
const handleClose = (
event: React.SyntheticEvent | Event,
reason?: string
@@ -148,7 +157,7 @@ const Interference = () => {
setLoading(true);
const gifData = await getGifFromServer(final_url);
if (gifData) {
- set_Success_Msg(
+ setSnackbarMessage(
"Interference model generated with barrier = " +
spacing_str +
", thickness = " +
@@ -157,11 +166,15 @@ const Interference = () => {
wave_str +
"!"
);
- setLoading(false);
- setSpacingSliderMoved(false);
- setSlitSepSliderMoved(false);
- setWaveSliderMoved(false);
+
+ }
+ else {
+ setSnackbarMessage("Failed to generate model.");
}
+ setLoading(false);
+ setSpacingSliderMoved(false);
+ setSlitSepSliderMoved(false);
+ setWaveSliderMoved(false);
}
setOpenSnackbar(true); // open snackbar
}
@@ -299,6 +312,16 @@ return (
+ setOpenSnackbar(false)}
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
+ >
+ setOpenSnackbar(false)} severity={severity}>
+ {snackbarMsg}
+
+
);
diff --git a/src/pages/Tunneling.tsx b/src/pages/Tunneling.tsx
index 5391799..2d40ad5 100644
--- a/src/pages/Tunneling.tsx
+++ b/src/pages/Tunneling.tsx
@@ -12,7 +12,8 @@ import {
Slider,
Typography,
CardContent,
- Card
+ Card,
+ AlertProps
} from "@mui/material";
import CircularProgress from '@mui/joy/CircularProgress';
import { Layout } from "antd";
@@ -47,16 +48,17 @@ const Tunneling = () => {
const [barrierSliderMoved, setBarrierSliderMoved] = useState(false);
const [thicknessSliderMoved, setThicknessSliderMoved] = useState(false);
const [waveSliderMoved, setWaveSliderMoved] = useState(false);
- const [success_msg, set_Success_Msg] = useState(
- "Tunneling model generated with barrier = " + barrier.toString() + ", thickness = " + thickness.toString() + ", and wave = " + wave.toString() + "!"
- );
- const [open, setOpenSnackbar] = useState(false);
+ const [snackbar_msg, setSnackbarMessage] = useState("Default tunneling model generated!");
+ const [severity, setSeverity] = useState('success');
+ const [openSnackBar, setOpenSnackbar] = useState(false);
async function getGifFromServer(request_url: string) {
try {
const response = await fetch(request_url, {method: 'GET'});
if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
+ console.error("Error fetching animation from server");
+ setSeverity('error');
+ return null;
}
const responseData = await response.text();
setAnimationJsHtml(responseData); // Adjust based on your API response structure
@@ -77,7 +79,8 @@ const Tunneling = () => {
setAnimationJsHtml(text);
});
} catch (error) {
- console.error('Failed to load default HTML content:', error);
+ setSnackbarMessage("Failed to load default model.");
+ setSeverity('error');
}
};
@@ -101,6 +104,12 @@ const Tunneling = () => {
}
}, [animationJsHtml]);
+ useEffect(() => {
+ if (snackbar_msg) {
+ setOpenSnackbar(true);
+ }
+ }, [snackbar_msg]);
+
// ========= handle functions =========
const handleClose = (
event: React.SyntheticEvent | Event,
@@ -154,7 +163,7 @@ const Tunneling = () => {
setLoading(true);
const gifData = await getGifFromServer(final_url);
if (gifData) {
- set_Success_Msg(
+ setSnackbarMessage(
"Tunneling model generated with barrier = " +
barrier_str +
", thickness = " +
@@ -163,11 +172,14 @@ const Tunneling = () => {
wave_str +
"!"
);
- setLoading(false);
- setBarrierSliderMoved(false);
- setThicknessSliderMoved(false);
- setWaveSliderMoved(false);
}
+ else {
+ setSnackbarMessage("Failed to generate model.");
+ }
+ setLoading(false);
+ setBarrierSliderMoved(false);
+ setThicknessSliderMoved(false);
+ setWaveSliderMoved(false);
}
setOpenSnackbar(true); // open snackbar
}
@@ -301,6 +313,16 @@ const Tunneling = () => {
>
+ setOpenSnackbar(false)}
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
+ >
+ setOpenSnackbar(false)} severity={severity}>
+ {snackbar_msg}
+
+
From 24d99117fa28a797d095b58a91157fc4354d6b73 Mon Sep 17 00:00:00 2001
From: Vy Vu <55815025+vudangbaovy@users.noreply.github.com>
Date: Wed, 11 Dec 2024 13:23:44 -0500
Subject: [PATCH 13/13] Update README.md
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 8407651..c9cea2c 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,7 @@
Computational Nano Lab, UFL
## Architecture Overview
-![image](https://github.com/user-attachments/assets/36da6434-28a5-4bd1-9704-8288bce7b5be)
-
+![image](https://github.com/user-attachments/assets/6abb6ef0-1a6d-466c-b85a-ab1bcdbac57a)
## Getting Started