Fix magnet profile paths and enable profile management via admin

This commit is contained in:
2026-08-14 20:34:00 +02:00
parent b5b33ad742
commit a46332245f
14 changed files with 153 additions and 17 deletions
+25
View File
@@ -0,0 +1,25 @@
### Isotope Table Admin Management
To manage the admin accounts for the Isotope Table application, use the following Django CLI commands.
#### Environment Setup
Ensure you are using the project's virtual environment. In this environment, the Python executable is located at:
`/home/markusro/sources/isotopetable/.venv/bin/python3`
#### Create a New Admin Account
To create a new superuser who can access the admin dashboard at `/admin/`:
```bash
/home/markusro/sources/isotopetable/.venv/bin/python3 manage.py createsuperuser
```
#### Change an Existing Admin Password
If you need to change the password for an existing user:
```bash
/home/markusro/sources/isotopetable/.venv/bin/python3 manage.py changepassword <username>
```
#### Uploading Magnet Profiles
Once logged into the admin panel at `http://127.0.0.1:8811/admin/` (or your local host), you can:
1. Navigate to **Field profiles**.
2. Click **Add field profile**.
3. Provide a name, upload the `.dat` file, and set the technical parameters (`step`, `cryo_length`, `reverse_offset`).
Binary file not shown.
+3
View File
@@ -123,3 +123,6 @@ STATIC_URL = 'static/'
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
+3 -1
View File
@@ -16,8 +16,10 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('isotopapp.urls')),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
+3 -1
View File
@@ -2,4 +2,6 @@ from django.contrib import admin
from isotopapp import models
# Register your models here.
admin.site.register(models.FieldProfile)
@admin.register(models.FieldProfile)
class FieldProfileAdmin(admin.ModelAdmin):
list_display = ('name', 'step', 'cryo_length', 'reverse_offset')
@@ -0,0 +1,40 @@
# Generated by Django 6.0.5 on 2026-08-14 18:23
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='FieldProfile',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, unique=True)),
('file', models.FileField(upload_to='magnet-profiles')),
('step', models.FloatField(default=0.0008333333333333334, help_text='Step size in m (or appropriate unit)')),
('cryo_length', models.FloatField(default=1113.0, help_text='Cryo length in mm')),
('reverse_offset', models.BooleanField(default=False, help_text='Check for Magnex style offset calculation')),
],
),
migrations.CreateModel(
name='Isotope',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('n_protons', models.IntegerField(help_text='Protons in isotope')),
('n_nucleons', models.IntegerField(help_text='Nucleons in isotope')),
('stable', models.BooleanField(help_text='Is isotope stable?')),
('symbol', models.CharField(help_text='Symbol of isotope', max_length=2)),
('name', models.CharField(help_text='Name of isotope', max_length=255)),
('spin_quantum_number', models.FloatField(help_text='Spin quantum number')),
('gamma', models.FloatField(help_text='Gyromagnetic ratio in MHz/T')),
('natural_abundance', models.FloatField(help_text='Natural abundance')),
('quadrupole_moment', models.FloatField(help_text='Quadrupole moment', null=True)),
],
),
]
+8 -1
View File
@@ -13,5 +13,12 @@ class Isotope(models.Model):
quadrupole_moment = models.FloatField(null=True, help_text="Quadrupole moment")
class FieldProfile(models.Model):
field_profile = models.FileField(upload_to='field_profile')
name = models.CharField(max_length=100, unique=True)
file = models.FileField(upload_to='magnet-profiles')
step = models.FloatField(default=0.0008333333333333334, help_text="Step size in m (or appropriate unit)")
cryo_length = models.FloatField(default=1113.0, help_text="Cryo length in mm")
reverse_offset = models.BooleanField(default=False, help_text="Check for Magnex style offset calculation")
def __str__(self):
return self.name
+7 -2
View File
@@ -45,8 +45,13 @@
<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="magnex_profile.dat">Magnex</option>
{% for m in magnets %}
<option value="{{ m.id }}">{{ m.name }}</option>
{% endfor %}
{% if not magnets %}
<option value="oxford.dat">Oxford</option>
<option value="magnex.dat">Magnex</option>
{% endif %}
</select>
</div>
<div class="col">
+36 -12
View File
@@ -6,6 +6,7 @@ import base64
from bokeh.models.axes import LinearAxis
from django.shortcuts import render
from django.utils.safestring import mark_safe
from django.conf import settings
import re
@@ -14,7 +15,7 @@ from bokeh.plotting import figure
from bokeh.embed import components
from bokeh.models import Label, Node, MathML, Range1d, Span, ColumnDataSource, DataTable, TableColumn
from isotopapp.models import Isotope
from isotopapp.models import Isotope, FieldProfile
# Create your views here.
def home(request):
@@ -23,7 +24,11 @@ def home(request):
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],})
magnets = FieldProfile.objects.all()
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],
'magnets': magnets,
})
def diffusion_form(request):
return render(request, 'diffusion_form.html', {})
@@ -151,16 +156,35 @@ def position(request):
isotope1 = Isotope.objects.filter(symbol=element1, n_nucleons=n1).get()
probe_length = float(request.GET.get('probe_length'))
print(os.path.abspath("."))
gradient_magnet = request.GET.get('magnet')
if gradient_magnet == "oxford_profile.dat":
step = 5e-3/6
cryo_length = 1113.0
offset = cryo_length / step - probe_length / step
elif gradient_magnet == "magnex_profile.dat":
step = 1e-3
cryo_length = 1262.2
offset = -(cryo_length / step - probe_length / step) # other direction
data = np.loadtxt(gradient_magnet)
magnet_id = request.GET.get('magnet')
try:
if magnet_id.isdigit():
magnet = FieldProfile.objects.get(pk=magnet_id)
else:
magnet = FieldProfile.objects.get(name=magnet_id)
step = magnet.step
cryo_length = magnet.cryo_length
if magnet.reverse_offset:
offset = -(cryo_length / step - probe_length / step)
else:
offset = cryo_length / step - probe_length / step
file_path = magnet.file.path
except (FieldProfile.DoesNotExist, ValueError):
if magnet_id == "oxford.dat":
step = 5e-3/6
cryo_length = 1113.0
offset = cryo_length / step - probe_length / step
file_path = os.path.join(settings.BASE_DIR, "magnet-profiles", "oxford.dat")
elif magnet_id == "magnex.dat":
step = 1e-3
cryo_length = 1262.2
offset = -(cryo_length / step - probe_length / step) # other direction
file_path = os.path.join(settings.BASE_DIR, "magnet-profiles", "magnex.dat")
else:
return render(request, 'home.html', {'error': f"Magnet profile {magnet_id} not found."})
data = np.loadtxt(file_path)
_z_coords = data[:,0]
_fields = data[:,1]
_gradients = data[:,2]
+28
View File
@@ -0,0 +1,28 @@
import argparse
import h5py as h5
from numpy import loadtxt
h = h5.File("profiles.h5","a")
p = loadtxt("oxford.dat")
h.create_dataset?
h.create_dataset?
h.create_dataset?
h.create_dataset(name=oxford, data=p)
h.create_dataset(name="oxford", data=p)
h.create_dataset?
h.get("oxford")
h.get("oxford").attrs
h.get("oxford").attrs.create("cryo_lenght", 1123)
h.get("oxford").attrs
h.get("oxford").attrs()
h.get("oxford").attrs.items
h.get("oxford").attrs.items()
h.get("oxford").attrs.keys()
h.get("oxford").attrs["cryo_length"]
h.get("oxford").attrs.create("cryo_length", 1123)
h.get("oxford").attrs["cryo_length"]
h.get("oxford").attrs.create("cryo_length", 1123, dtype=float)
h.get("oxford").attrs["cryo_length"]
Binary file not shown.