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
19 changes: 18 additions & 1 deletion src/diffcalc_API/errors/HklCalculation.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from typing import Tuple
from typing import Optional, Tuple, Union

import numpy as np
from diffcalc.hkl.calc import HklCalculation

from diffcalc_API.errorDefinitions import DiffcalcAPIException, ErrorCodes, allResponses


class codes(ErrorCodes):
check_valid_miller_indices = 400
check_valid_scan_bounds = 400
calculate_UB_matrix = 400


responses = {code: allResponses[code] for code in np.unique(codes().all_codes())}
Expand All @@ -32,3 +34,18 @@ def check_valid_scan_bounds(start: float, stop: float, inc: float):
),
)
return


def calculate_UB_matrix(
hkl: HklCalculation,
firstTag: Optional[Union[int, str]],
secondTag: Optional[Union[int, str]],
) -> None:
try:
hkl.ubcalc.calc_ub(firstTag, secondTag)
except Exception as e:
raise DiffcalcAPIException(
status_code=codes.calculate_UB_matrix,
detail=f"Error calculating UB matrix: {str(e)}",
)
return
18 changes: 1 addition & 17 deletions src/diffcalc_API/errors/UBCalculation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Union
from typing import Union

import numpy as np
from diffcalc.hkl.calc import HklCalculation
Expand All @@ -14,7 +14,6 @@ class codes(ErrorCodes):
get_reflection = 403
get_orientation = 403
check_property_is_valid = 400
calculate_UB_matrix = 400


responses = {code: allResponses[code] for code in np.unique(codes().all_codes())}
Expand Down Expand Up @@ -68,18 +67,3 @@ def check_property_is_valid(property: str) -> None:
detail=f"invalid property. Choose one of: {VectorProperties}",
)
return


def calculate_UB_matrix(
hkl: HklCalculation,
firstTag: Optional[Union[int, str]],
secondTag: Optional[Union[int, str]],
) -> None:
try:
hkl.ubcalc.calc_ub(firstTag, secondTag)
except Exception as e:
raise DiffcalcAPIException(
status_code=codes.calculate_UB_matrix,
detail=f"Error calculating UB matrix: {e.__str__()}",
)
return
10 changes: 8 additions & 2 deletions src/diffcalc_API/routes/Constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from diffcalc.hkl.calc import HklCalculation
from diffcalc.hkl.constraints import Constraints
from fastapi import APIRouter, Body, Depends
from fastapi import APIRouter, Body, Depends, Response

from diffcalc_API.config import constraintsWithNoValue
from diffcalc_API.errors.Constraints import check_constraint_exists
Expand All @@ -15,6 +15,13 @@
singleConstraintType = Union[Tuple[str, float], str]


@router.get("/{name}")
async def get_constraints_status(
name: str, hklCalc: HklCalculation = Depends(unpickleHkl)
):
return Response(content=str(hklCalc.constraints), media_type="application/text")


@router.put("/{name}/set")
async def set_constraints(
name: str,
Expand All @@ -33,7 +40,6 @@ async def set_constraints(
return {"message": f"constraints updated (replaced) for crystal {name}"}


# is patch the correct choice here? What about delete instead?
@router.patch("/{name}/unconstrain/{property}")
async def remove_constraint(
name: str,
Expand Down
24 changes: 21 additions & 3 deletions src/diffcalc_API/routes/HklCalculation.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from itertools import product
from typing import Dict, List, Tuple, Union
from pathlib import Path
from typing import Callable, Dict, List, Optional, Tuple, Union

import numpy as np
from diffcalc.hkl.calc import HklCalculation
from diffcalc.hkl.geometry import Position
from fastapi import APIRouter, Depends, Query
from fastapi import APIRouter, Depends, Query, Response

from diffcalc_API.errors.HklCalculation import (
calculate_UB_matrix,
check_valid_miller_indices,
check_valid_scan_bounds,
)
from diffcalc_API.fileHandling import unpickleHkl
from diffcalc_API.fileHandling import supplyPersist, unpickleHkl

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

Expand All @@ -19,6 +21,22 @@
positionType = Tuple[float, float, float]


@router.get("/{name}/UB")
async def calculate_UB(
name: str,
firstTag: Optional[Union[int, str]] = Query(default=None, example="refl1"),
secondTag: Optional[Union[int, str]] = Query(default=None, example="plane"),
hklCalc: HklCalculation = Depends(unpickleHkl),
persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist),
):
calculate_UB_matrix(hklCalc, firstTag, secondTag)

persist(hklCalc, name)
return Response(
content=str(np.round(hklCalc.ubcalc.UB, 6)), media_type="application/text"
)


@router.get("/{name}/position/lab")
async def lab_position_from_miller_indices(
name: str,
Expand Down
26 changes: 7 additions & 19 deletions src/diffcalc_API/routes/UBCalculation.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import json
from pathlib import Path
from typing import Callable, Optional, Tuple, Union
from typing import Callable, Tuple, Union

import numpy as np
from diffcalc.hkl.calc import HklCalculation
from diffcalc.hkl.geometry import Position
from fastapi import APIRouter, Body, Depends, Query
from fastapi import APIRouter, Body, Depends, Response

from diffcalc_API.errors.UBCalculation import (
calculate_UB_matrix,
check_params_not_empty,
check_property_is_valid,
get_orientation,
Expand All @@ -27,6 +24,11 @@
router = APIRouter(prefix="/ub", tags=["ub"])


@router.get("/{name}")
async def get_UB_status(name: str, hklCalc: HklCalculation = Depends(unpickleHkl)):
return Response(content=str(hklCalc.ubcalc), media_type="application/text")


@router.put("/{name}/reflection")
async def add_reflection(
name: str,
Expand Down Expand Up @@ -172,20 +174,6 @@ async def modify_property(
return {"message": f"{property} set for UB calculation of crystal {name}"}


@router.get("/{name}/UB")
async def calculate_UB(
name: str,
firstTag: Optional[Union[int, str]] = Query(default=None, example="refl1"),
secondTag: Optional[Union[int, str]] = Query(default=None, example="plane"),
hklCalc: HklCalculation = Depends(unpickleHkl),
persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist),
):
calculate_UB_matrix(hklCalc, firstTag, secondTag)

persist(hklCalc, name)
return json.dumps(np.round(hklCalc.ubcalc.UB, 6).tolist())


@router.delete("/{name}/reflection")
async def delete_reflection(
name: str,
Expand Down
4 changes: 2 additions & 2 deletions src/diffcalc_API/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
async def diffcalc_exception_handler(request: Request, exc: DiffcalcException):
return responses.JSONResponse(
status_code=400,
content={"message": exc.__str__(), "type": str(type(exc))},
content={"message": str(exc), "type": str(type(exc))},
)


Expand All @@ -46,7 +46,7 @@ async def server_exceptions_middleware(request: Request, call_next):

return responses.JSONResponse(
status_code=500,
content={"message": e.__str__(), "type": str(type(e))},
content={"message": str(e), "type": str(type(e))},
)


Expand Down
21 changes: 21 additions & 0 deletions tests/test_hklcalc.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,24 @@ def test_invalid_scans(client: TestClient):
)

assert invalidWavelengthScan.status_code == codes.check_valid_scan_bounds


def test_calculate_UB(client: TestClient):
response = client.get(
"/calculate/test/UB", params={"firstTag": "refl1", "secondTag": "plane"}
)
expected_UB = (
"[[ 1.27889 -0. 0. ], [-0. 1.278111 0.04057 ],"
" [-0. -0.044633 1.161768]]"
)

assert response.status_code == 200
assert response.text.replace("\n", ", ") == expected_UB


def test_calculate_UB_fails_when_incorrect_tags(client: TestClient):
response = client.get(
"/calculate/test/UB", params={"firstTag": "one", "secondTag": "two"}
)

assert response.status_code == codes.calculate_UB_matrix
20 changes: 0 additions & 20 deletions tests/test_ubcalc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import ast
from pathlib import Path

import numpy as np
Expand Down Expand Up @@ -202,22 +201,3 @@ def test_modify_non_existent_property(client: TestClient):
json=[0, 0, 1],
)
assert response.status_code == codes.check_property_is_valid


def test_calculate_UB(client: TestClient):
dummyHkl.ubcalc.add_reflection([0, 0, 1], Position(7, 0, 10, 0, 0, 0), 12, "foo")
dummyHkl.ubcalc.add_orientation([0, 1, 0], [0, 1, 0], None, "bar")
dummyHkl.ubcalc.set_lattice(name="test", a=2)

response = client.get("/ub/test/UB", params={"firstTag": "foo", "secondTag": "bar"})

expected_UB = [[3.141593, 0, 0], [0, 3.139679, 0.10964], [-0, -0.10964, 3.139679]]

assert response.status_code == 200
assert ast.literal_eval(response._content.decode().replace('"', "")) == expected_UB


def test_calculate_UB_fails_when_incorrect_tags(client: TestClient):
response = client.get("/ub/test/UB", params={"firstTag": "one", "secondTag": "two"})

assert response.status_code == codes.calculate_UB_matrix