Fix magnet profile paths and enable profile management via admin
This commit is contained in:
@@ -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.
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user