diff --git a/isotables/README.md b/isotables/README.md new file mode 100644 index 0000000..9f96698 --- /dev/null +++ b/isotables/README.md @@ -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 +``` + +#### 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`). diff --git a/isotables/db.sqlite3 b/isotables/db.sqlite3 index d07dd54..58f2c76 100644 Binary files a/isotables/db.sqlite3 and b/isotables/db.sqlite3 differ diff --git a/isotables/isotables/settings.py b/isotables/isotables/settings.py index 418c97d..8afb1a1 100644 --- a/isotables/isotables/settings.py +++ b/isotables/isotables/settings.py @@ -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') diff --git a/isotables/isotables/urls.py b/isotables/isotables/urls.py index 8ec20d5..c3f040a 100644 --- a/isotables/isotables/urls.py +++ b/isotables/isotables/urls.py @@ -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) diff --git a/isotables/isotopapp/admin.py b/isotables/isotopapp/admin.py index 6611f11..dc47350 100644 --- a/isotables/isotopapp/admin.py +++ b/isotables/isotopapp/admin.py @@ -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') diff --git a/isotables/isotopapp/migrations/0001_initial.py b/isotables/isotopapp/migrations/0001_initial.py new file mode 100644 index 0000000..e7a7d0b --- /dev/null +++ b/isotables/isotopapp/migrations/0001_initial.py @@ -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)), + ], + ), + ] diff --git a/isotables/isotopapp/migrations/__init__.py b/isotables/isotopapp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/isotables/isotopapp/models.py b/isotables/isotopapp/models.py index 13e7ffa..d20674a 100644 --- a/isotables/isotopapp/models.py +++ b/isotables/isotopapp/models.py @@ -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 diff --git a/isotables/isotopapp/templates/sfg.html b/isotables/isotopapp/templates/sfg.html index fcd3b26..912fac4 100644 --- a/isotables/isotopapp/templates/sfg.html +++ b/isotables/isotopapp/templates/sfg.html @@ -45,8 +45,13 @@
diff --git a/isotables/isotopapp/views.py b/isotables/isotopapp/views.py index 2346afe..ab84f63 100644 --- a/isotables/isotopapp/views.py +++ b/isotables/isotopapp/views.py @@ -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"{i.n_nucleons}{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"{i.n_nucleons}{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] diff --git a/isotables/magnet-profiles/add_profile.py b/isotables/magnet-profiles/add_profile.py new file mode 100644 index 0000000..058e265 --- /dev/null +++ b/isotables/magnet-profiles/add_profile.py @@ -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"] + diff --git a/isotables/isotopapp/magnex_profile.dat b/isotables/magnet-profiles/magnex.dat similarity index 100% rename from isotables/isotopapp/magnex_profile.dat rename to isotables/magnet-profiles/magnex.dat diff --git a/isotables/isotopapp/oxford_profile.dat b/isotables/magnet-profiles/oxford.dat similarity index 100% rename from isotables/isotopapp/oxford_profile.dat rename to isotables/magnet-profiles/oxford.dat diff --git a/isotables/magnet-profiles/profiles.h5 b/isotables/magnet-profiles/profiles.h5 new file mode 100644 index 0000000..56a0124 Binary files /dev/null and b/isotables/magnet-profiles/profiles.h5 differ