Added gradient calculation

This commit is contained in:
Markus Rosenstihl 2025-04-03 22:56:03 +02:00
parent 33bf3d6833
commit 11729f67e5
5 changed files with 2247 additions and 2 deletions

View File

@ -0,0 +1,81 @@
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link href=”https://cdn.pydata.org/bokeh/release/bokeh-3.7.1.min.css" rel=”stylesheet” type=”text/css”>
<link href=”https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.7.1.min.css" rel=”stylesheet” type=”text/css”>
</head>
<body>
<div class="center">
<h1>Isotopes</h1>
<table class="table w-auto table-responsive-sm table-striped table-hover table-bordered">
<caption>
Table downloaded from <a href="https://easyspin.org/documentation/isotopetable.html">easyspin.org</a>
(2023-07-29 markusro)
</caption>
<thead class="table-dark">
<tr>
<th scope="col">N</th>
<th scope="col">Symbol</th>
<th scope="col">Name</th>
<th scope="col">f<sub>0</sub> in MHz</th>
<th scope="col">Spin</th>
<th scope="col">Nat. ab. in %</th>
<th scope="col">&gamma; in MHz/T</th>
<th scope="col">Sens. in %(<sup>1</sup>H)</th>
</tr>
</thead>
<tbody>
{% for attr in ans %}
<tr>
{% for i in attr %}
<td>{{ i }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{{ div| safe }}
<div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/latest.js"
integrity="sha512-nUTIGJLS9aRMjQaRwpCiC+0Y2RzgW4sufFhFgyjHgn15DXLSfoVUaEa83CsNe2FSJpLXtfgdVfgL7a0lrbcBWA=="
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.7.1.min.js"></script>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.7.1.min.js"></script>
{{ script| safe }}
</div>
<a href="{% url 'home' %}">Go Back</a>
</div>
</body>
<style>
.center {
margin: auto;
width: 40%;
padding: 10px;
}
caption {
caption-side: bottom;
padding: 8px;
font-weight: normal;
font-size: 0.8rem;
text-align: left;
}
.table-striped {
--bs-table-striped-bg: rgba(213, 217, 255, 0.7);
}
</style>

View File

@ -0,0 +1,77 @@
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<style>
.center {
margin: auto;
width: 60%;
border: 3px solid #90befb;
border: 3px solid #a5addb;
padding: 10px;
}
</style>
<div class="container text-left">
<h1>SFG Position Calculator</h1>
<form action="position">
<div class="row row-cols-6">
<div class="col"><label class="form-label">Source isotope:</label></div>
<div class="col">
<select name="isotope1" class="form-select" size="1">
{% for i in isotopes %}
<option value="{{ i.0 }}">{{ i.1 }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row row-cols-6">
<div class="col"><label class="form-label">Source frequency in MHz:</label></div>
<div class="col">
<input type="number" name="freq" class="form-control" step="any" value=100
placeholder="Larmor frequency in MHz">
</div>
</div>
<div class="row row-cols-6">
<label class="form-label">Destination isotope:</label>
<div class="col">
<select name="isotope2" class="form-select" size="1">
{% for i in isotopes %}
<option value="{{ i.0 }}">{{ i.1 }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row row-cols-6">
<label class="form-label">Probe length:</label>
<div class="col">
<input type="number" name="probe_length" class="form-control" step="any"
placeholder="Probe length in mm">
</div>
</div>
<div class="row row-cols-6">
<label class="form-label">Magnet</label>
<div class="col">
<select name="magnet" class="form-select" size="1">
<option value="oxford_profile.dat">Oxford</option>
<option value="oxford_profile.dat">Magnex</option>
</select>
</div>
</div>
<div class="row row-cols-6">
<label class="form-label">Gradient in T/m:<br>(assuming &#x2300;5mm)</label>
<div class="col"><input type="number" name="gradient" class="form-control" step="any"
placeholder="Gradient in T/m"></div>
<div class="col">
<button type="submit" name="gradient_search" class="btn btn-primary btn-sm">Get position</button>
</div>
</div>
</form>
</div>
<div>
{{ ans }}
</div>

View File

@ -3,6 +3,8 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.home, name='home'), path('', views.home, name='home'),
path('result/', views.result, name='result'), path('result/', views.result, name='result'),
path('sfg', views.sfg, name='sfg'),
path('position/', views.position, name='position'),
] ]

View File

@ -1,14 +1,18 @@
import os
from math import pi from math import pi
from io import BytesIO from io import BytesIO
import base64 import base64
from bokeh.models.axes import LinearAxis
from django.shortcuts import render from django.shortcuts import render
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
import re import re
import numpy as np
from bokeh.plotting import figure from bokeh.plotting import figure
from bokeh.embed import components from bokeh.embed import components
from bokeh.models import Label, Node, MathML from bokeh.models import Label, Node, MathML, Range1d, Span
from isotopapp.models import Isotope from isotopapp.models import Isotope
# Create your views here. # Create your views here.
@ -17,6 +21,10 @@ def home(request):
isotopes = [i for i in Isotope.objects.all() if (i.gamma != 0 or i.stable)] isotopes = [i for i in Isotope.objects.all() if (i.gamma != 0 or i.stable)]
return render(request, 'home.html', {'isotopes': [[f"{i.n_nucleons}{i.symbol}", mark_safe(f"<sup>{i.n_nucleons}</sup>{i.symbol}")] for i in isotopes],}) return render(request, 'home.html', {'isotopes': [[f"{i.n_nucleons}{i.symbol}", mark_safe(f"<sup>{i.n_nucleons}</sup>{i.symbol}")] for i in isotopes],})
def sfg(request):
isotopes = [i for i in Isotope.objects.all() if (i.gamma != 0 or i.stable)]
return render(request, 'sfg.html', {'isotopes': [[f"{i.n_nucleons}{i.symbol}", mark_safe(f"<sup>{i.n_nucleons}</sup>{i.symbol}")] for i in isotopes],})
def extract_isotope_parts(isotope_str): def extract_isotope_parts(isotope_str):
"""Extracts the number and element from an isotope string (e.g., '23Na').""" """Extracts the number and element from an isotope string (e.g., '23Na')."""
print(isotope_str) print(isotope_str)
@ -131,3 +139,96 @@ def result(request):
else: else:
ans = [] ans = []
return render(request, 'result.html', {'ans': ans, 'script': script, 'div': div}) return render(request, 'result.html', {'ans': ans, 'script': script, 'div': div})
def position(request):
print(request)
n1, element1 = extract_isotope_parts(request.GET.get('isotope1'))
isotope1 = Isotope.objects.filter(symbol=element1, n_nucleons=n1).get()
print(os.path.abspath("."))
data = np.loadtxt(request.GET.get('magnet'))
_z_coords = data[:,0]
_fields = data[:,1]
_gradients = data[:,2]
freq = float(request.GET.get('freq'))
field_T = freq / isotope1.gamma
sample_diameter = 5e-3
gradient = float(request.GET.get('gradient'))
# create a plot (bokeh)
TOOLTIPS = [
("index", "$index"),
("(x,y)", "($x, $y)"),
("desc", "@desc"),
]
plot = figure(outer_width=500, outer_height=500, match_aspect=False, tooltips=TOOLTIPS)
frame_left = Node(target="frame", symbol="left", offset=5)
frame_bottom = Node(target="frame", symbol="bottom", offset=0)
frame_top = Node(target="frame", symbol="top", offset=0)
#plot.ellipse(x=[0], y=[0], width=5, height=5, color="#D5D9FF", alpha=0.8, line_width=1, line_color="black")
#plot.ellipse(x=[0], y= [2.5], width=5, height=5, color="#D5D9FF", alpha=0.4, line_width=1, line_color="black")
#plot.ellipse(x=[0], y=[-2.5], width=5, height=5, color="#D5D9FF", alpha=0.4, line_width=1, line_color="black")
plot.xaxis[0].axis_label = 'z in mm'
plot.yaxis[0].axis_label = 'B0 in T'
plot.line(x=_z_coords*1e3, y=_fields, color="navy", line_width=2)
plot.yaxis[0].axis_label_text_color = "navy"
plot.y_range = Range1d(-10, 10)
plot.extra_y_ranges['gradient'] = Range1d(-200, 200)
plot.line(x=_z_coords * 1e3, y=_gradients, color="crimson", line_width=2 , y_range_name="gradient")
ax2 = LinearAxis(y_range_name="gradient", axis_label="g in T/m")
ax2.axis_label_text_color = "crimson"
plot.add_layout(ax2, 'left')
# find fields where _fields == field:
pos_threshold_indices = np.where(np.diff(np.sign(_fields + field_T)) != 0)[0]
neg_threshold_indices = np.where(np.diff(np.sign(_fields - field_T)) != 0)[0]
indices = np.concatenate((pos_threshold_indices, neg_threshold_indices))
for p in indices:
vline = Span(location=_z_coords[p]*1e3, dimension='height', line_color='gray', line_width=1)
plot.renderers.extend([vline])
label = Label(x=_z_coords[p]*1e3, y=_fields[p]+1, text=f"{_z_coords[p]*1e3:.2f},{_gradients[p]:.1f}T/m", text_baseline="middle",
text_align="center", text_font_size="11pt")
plot.add_layout(label)
plot.circle(x=_z_coords[indices]*1e3, y=_fields[indices], radius=2, color="gray")
plot.circle(x=_z_coords[indices]*1e3, y=_gradients[indices], radius=2, color="gray",y_range_name="gradient" )
hline1 = Span(location=field_T, dimension='width', line_color='gray', line_width=1)
hline2 = Span(location=-field_T, dimension='width', line_color='gray', line_width=1)
plot.renderers.extend([hline1, hline2])
close_isotopes = []
for isotope in Isotope.objects.all():
if isotope.gamma == 0: continue
if not isotope.stable: continue
z = (freq/isotope.gamma-field_T)/gradient
if abs(z) <= sample_diameter:
i_info = isotope_info(isotope, field_T)
#i_info[3] = f"{z*1e3:.1f} mm"
close_isotopes.append(i_info)
#plot.rect(x=[0], y=[z*1e3], width=5, height=0.2, color="black", alpha=0.6)
#label = Label(x=2.6, y=z*1e3, text=f"{isotope.n_nucleons}{isotope.symbol}", text_baseline="middle", text_align="left", text_font_size="16pt")
#plot.add_layout(label)
citation = Label(
x=frame_left,
y=frame_bottom,
anchor="bottom_left",
text=f"{isotope1.n_nucleons}{isotope1.symbol}: {freq:.1f} MHz\ng={gradient:.1f} T/m\n5 mm sample dia.",
padding=5,
border_radius=5,
border_line_color="#D5D9FF", background_fill_color="white",
)
plot.add_layout(citation)
# boke plot
script, div = components(plot)
ans = sorted(close_isotopes, key=lambda x: float(x[3]))
return render(request, 'posiiton.html', {'ans': ans, 'script': script, 'div': div})

1984
isotables/oxford_profile.dat Normal file

File diff suppressed because it is too large Load Diff