Skip to content
This repository was archived by the owner on May 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/diffcalc_API/errors/hkl.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

import numpy as np

from diffcalc_API.errors.definitions import (
Expand All @@ -16,8 +18,10 @@ class ErrorCodes(ErrorCodesBase):


class InvalidMillerIndicesError(DiffcalcAPIException):
def __init__(self) -> None:
self.detail = "At least one of the hkl indices must be non-zero"
def __init__(self, detail: Optional[str] = None) -> None:
self.detail = (
"At least one of the hkl indices must be non-zero" if not detail else detail
)
self.status_code = ErrorCodes.INVALID_MILLER_INDICES


Expand Down
13 changes: 8 additions & 5 deletions src/diffcalc_API/examples/ub.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
AddReflectionParams,
EditOrientationParams,
EditReflectionParams,
HklModel,
PositionModel,
SetLatticeParams,
XyzModel,
)

add_reflection: AddReflectionParams = AddReflectionParams(
**{
"hkl": [0, 0, 1],
"position": [7.31, 0.0, 10.62, 0, 0.0, 0],
"hkl": HklModel(h=0, k=0, l=1),
"position": PositionModel(mu=7.31, delta=0.0, nu=10.62, eta=0, chi=0.0, phi=0),
"energy": 12.39842,
"tag": "refl1",
}
Expand All @@ -21,15 +24,15 @@

add_orientation: AddOrientationParams = AddOrientationParams(
**{
"hkl": [0, 1, 0],
"xyz": [0, 1, 0],
"hkl": HklModel(h=0, k=1, l=0),
"xyz": XyzModel(x=0, y=1, z=0),
"tag": "plane",
}
)

edit_orientation: EditOrientationParams = EditOrientationParams(
**{
"hkl": (0, 1, 0),
"hkl": HklModel(h=0, k=1, l=0),
"tag_or_idx": "plane",
}
)
Expand Down
45 changes: 32 additions & 13 deletions src/diffcalc_API/models/ub.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
from typing import Optional, Tuple, Union
from typing import Optional, Union

from pydantic import BaseModel


class HklModel(BaseModel):
h: float
k: float
l: float


class XyzModel(BaseModel):
x: float
y: float
z: float


class PositionModel(BaseModel):
mu: float
delta: float
nu: float
eta: float
chi: float
phi: float


class SetLatticeParams(BaseModel):
system: Optional[Union[str, float]] = None
a: Optional[float] = None
Expand All @@ -14,32 +35,30 @@ class SetLatticeParams(BaseModel):


class AddReflectionParams(BaseModel):
hkl: Tuple[float, float, float]
position: Tuple[
float, float, float, float, float, float
] # allows easier user input
hkl: HklModel
position: PositionModel
energy: float
tag: Optional[str] = None


class AddOrientationParams(BaseModel):
hkl: Tuple[float, float, float]
xyz: Tuple[float, float, float]
position: Optional[Tuple[float, float, float, float, float, float]] = None
hkl: HklModel
xyz: XyzModel
position: Optional[PositionModel] = None
tag: Optional[str] = None


class EditReflectionParams(BaseModel):
hkl: Optional[Tuple[float, float, float]] = None
position: Optional[Tuple[float, float, float, float, float, float]] = None
hkl: Optional[HklModel] = None
position: Optional[PositionModel] = None
energy: Optional[float] = None
tag_or_idx: Union[int, str]


class EditOrientationParams(BaseModel):
hkl: Optional[Tuple[float, float, float]] = None
xyz: Optional[Tuple[float, float, float]] = None
position: Optional[Tuple[float, float, float, float, float, float]] = None
hkl: Optional[HklModel] = None
xyz: Optional[XyzModel] = None
position: Optional[PositionModel] = None
tag_or_idx: Union[int, str]


Expand Down
27 changes: 14 additions & 13 deletions src/diffcalc_API/routes/hkl.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
from typing import Optional, Tuple, Union
from typing import List, Optional, Union

from fastapi import APIRouter, Depends, Query

from diffcalc_API.models.ub import HklModel, PositionModel
from diffcalc_API.services import hkl as service
from diffcalc_API.stores.protocol import HklCalcStore, get_store

router = APIRouter(prefix="/hkl", tags=["hkl"])


SingleConstraint = Union[Tuple[str, float], str]
PositionType = Tuple[float, float, float]


@router.get("/{name}/UB")
async def calculate_ub(
name: str,
Expand All @@ -27,7 +24,8 @@ async def calculate_ub(
@router.get("/{name}/position/lab")
async def lab_position_from_miller_indices(
name: str,
miller_indices: Tuple[float, float, float] = Query(example=[0, 0, 1]),
# miller_indices: List[float] = Query(example=[0, 0, 1]),
miller_indices: HklModel = Depends(),
wavelength: float = Query(..., example=1.0),
store: HklCalcStore = Depends(get_store),
collection: Optional[str] = Query(default=None, example="B07"),
Expand All @@ -42,8 +40,9 @@ async def lab_position_from_miller_indices(
@router.get("/{name}/position/hkl")
async def miller_indices_from_lab_position(
name: str,
pos: Tuple[float, float, float, float, float, float] = Query(
..., example=[7.31, 0, 10.62, 0, 0, 0]
pos: PositionModel = Depends(
# ..., example={"mu": 7.31, "delta": 0, "nu": 10.62,
# "eta": 0, "chi": 0, "phi": 0}
),
wavelength: float = Query(..., example=1.0),
store: HklCalcStore = Depends(get_store),
Expand All @@ -58,9 +57,9 @@ async def miller_indices_from_lab_position(
@router.get("/{name}/scan/hkl")
async def scan_hkl(
name: str,
start: PositionType = Query(..., example=(1, 0, 1)),
stop: PositionType = Query(..., example=(2, 0, 2)),
inc: PositionType = Query(..., example=(0.1, 0, 0.1)),
start: List[float] = Query(..., example=[1, 0, 1]),
stop: List[float] = Query(..., example=[2, 0, 2]),
inc: List[float] = Query(..., example=(0.1, 0, 0.1)),
wavelength: float = Query(..., example=1),
store: HklCalcStore = Depends(get_store),
collection: Optional[str] = Query(default=None, example="B07"),
Expand All @@ -77,7 +76,8 @@ async def scan_wavelength(
start: float = Query(..., example=1.0),
stop: float = Query(..., example=2.0),
inc: float = Query(..., example=0.2),
hkl: PositionType = Query(..., example=(1, 0, 1)),
# hkl: PositionType = Query(..., example=(1, 0, 1)),
hkl: HklModel = Depends(),
store: HklCalcStore = Depends(get_store),
collection: Optional[str] = Query(default=None, example="B07"),
):
Expand All @@ -94,7 +94,8 @@ async def scan_constraint(
start: float = Query(..., example=1),
stop: float = Query(..., example=4),
inc: float = Query(..., example=1),
hkl: PositionType = Query(..., example=(1, 0, 1)),
# hkl: PositionType = Query(..., example=(1, 0, 1)),
hkl: HklModel = Depends(),
wavelength: float = Query(..., example=1.0),
store: HklCalcStore = Depends(get_store),
collection: Optional[str] = Query(default=None, example="B07"),
Expand Down
5 changes: 3 additions & 2 deletions src/diffcalc_API/routes/ub.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Tuple
from typing import Optional

from fastapi import APIRouter, Body, Depends, Query

Expand All @@ -11,6 +11,7 @@
DeleteParams,
EditOrientationParams,
EditReflectionParams,
HklModel,
SetLatticeParams,
)
from diffcalc_API.services import ub as service
Expand Down Expand Up @@ -152,7 +153,7 @@ async def set_lattice(
async def modify_property(
name: str,
property: str,
target_value: Tuple[float, float, float] = Body(..., example=[1, 0, 0]),
target_value: HklModel = Body(..., example={"h": 1, "k": 0, "l": 0}),
store: HklCalcStore = Depends(get_store),
collection: Optional[str] = Query(default=None, example="B07"),
):
Expand Down
3 changes: 3 additions & 0 deletions src/diffcalc_API/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import traceback
from typing import Optional

from diffcalc.util import DiffcalcException
Expand Down Expand Up @@ -46,6 +47,8 @@ async def server_exceptions_middleware(request: Request, call_next):
return await call_next(request)
except Exception as e:
# you probably want some kind of logging here
tb = traceback.format_exc()
print(tb)

return responses.JSONResponse(
status_code=500,
Expand Down
37 changes: 21 additions & 16 deletions src/diffcalc_API/services/hkl.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from itertools import product
from typing import Any, Dict, List, Optional, Tuple, Union
from typing import Dict, List, Optional, Tuple, Union

import numpy as np
from diffcalc.hkl.geometry import Position

from diffcalc_API.errors.hkl import InvalidMillerIndicesError, InvalidScanBoundsError
from diffcalc_API.models.ub import HklModel, PositionModel
from diffcalc_API.stores.protocol import HklCalcStore

PositionType = Tuple[float, float, float]


async def lab_position_from_miller_indices(
name: str,
miller_indices: Tuple[float, float, float],
miller_indices: HklModel,
wavelength: float,
store: HklCalcStore,
collection: Optional[str],
Expand All @@ -22,33 +21,39 @@ async def lab_position_from_miller_indices(
if all([idx == 0 for idx in miller_indices]):
raise InvalidMillerIndicesError()

all_positions = hklcalc.get_position(*miller_indices, wavelength)
all_positions = hklcalc.get_position(*miller_indices.dict().values(), wavelength)

return combine_lab_position_results(all_positions)


async def miller_indices_from_lab_position(
name: str,
pos: Tuple[float, float, float, float, float, float],
pos: PositionModel,
wavelength: float,
store: HklCalcStore,
collection: Optional[str],
) -> Tuple[Any, ...]:
) -> HklModel:
hklcalc = await store.load(name, collection)
position = hklcalc.get_hkl(Position(*pos), wavelength)
return tuple(np.round(position, 16))
hkl = np.round(hklcalc.get_hkl(Position(**pos.dict()), wavelength), 16)
return HklModel(h=hkl[0], k=hkl[1], l=hkl[2])


async def scan_hkl(
name: str,
start: PositionType,
stop: PositionType,
inc: PositionType,
start: List[float],
stop: List[float],
inc: List[float],
wavelength: float,
store: HklCalcStore,
collection: Optional[str],
) -> Dict[str, List[Dict[str, float]]]:
hklcalc = await store.load(name, collection)

if (len(start) != 3) or (len(stop) != 3) or (len(inc) != 3):
raise InvalidMillerIndicesError(
detail="start, stop and inc must have three floats for each miller index."
)

axes_values = [
generate_axis(start[i], stop[i], inc[i]) if inc[i] != 0 else [0]
for i in range(3)
Expand All @@ -71,7 +76,7 @@ async def scan_wavelength(
start: float,
stop: float,
inc: float,
hkl: PositionType,
hkl: HklModel,
store: HklCalcStore,
collection: Optional[str],
) -> Dict[str, List[Dict[str, float]]]:
Expand All @@ -84,7 +89,7 @@ async def scan_wavelength(
result = {}

for wavelength in wavelengths:
all_positions = hklcalc.get_position(*hkl, wavelength)
all_positions = hklcalc.get_position(*hkl.dict().values(), wavelength)
result[f"{wavelength}"] = combine_lab_position_results(all_positions)

return result
Expand All @@ -96,7 +101,7 @@ async def scan_constraint(
start: float,
stop: float,
inc: float,
hkl: PositionType,
hkl: HklModel,
wavelength: float,
store: HklCalcStore,
collection: Optional[str],
Expand All @@ -109,7 +114,7 @@ async def scan_constraint(
result = {}
for value in np.arange(start, stop + inc, inc):
setattr(hklcalc, constraint, value)
all_positions = hklcalc.get_position(*hkl, wavelength)
all_positions = hklcalc.get_position(*hkl.dict().values(), wavelength)
result[f"{value}"] = combine_lab_position_results(all_positions)

return result
Expand Down
Loading