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
4 changes: 3 additions & 1 deletion src/diffcalc_API/database.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import motor.motor_asyncio
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase

client: AsyncIOMotorClient = motor.motor_asyncio.AsyncIOMotorClient()
client: AsyncIOMotorClient = motor.motor_asyncio.AsyncIOMotorClient(
"172.23.169.16:27017"
)
database: AsyncIOMotorDatabase = client.test_db
22 changes: 10 additions & 12 deletions src/diffcalc_API/errors/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,21 @@
from diffcalc_API.errors.definitions import (
ALL_RESPONSES,
DiffcalcAPIException,
ErrorCodes,
ErrorCodesBase,
)


class Codes(ErrorCodes):
CHECK_CONSTRAINT_EXISTS = 400
class ErrorCodes(ErrorCodesBase):
INVALID_CONSTRAINT = 400


responses = {code: ALL_RESPONSES[code] for code in np.unique(Codes.all_codes())}
responses = {code: ALL_RESPONSES[code] for code in np.unique(ErrorCodes.all_codes())}


def check_constraint_exists(constraint: str) -> None:
if constraint not in ALL_CONSTRAINTS:
raise DiffcalcAPIException(
status_code=Codes.CHECK_CONSTRAINT_EXISTS,
detail=(
f"property {constraint} does not exist as a valid constraint."
f" Choose one of {ALL_CONSTRAINTS}"
),
class InvalidConstraintError(DiffcalcAPIException):
def __init__(self, constraint: str):
self.detail = (
f"property {constraint} does not exist as a valid constraint."
f" Valid constraints are: {ALL_CONSTRAINTS}"
)
self.status_code = ErrorCodes.INVALID_CONSTRAINT
9 changes: 1 addition & 8 deletions src/diffcalc_API/errors/definitions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from enum import IntEnum
from typing import Any, Dict, List, Union

from diffcalc.util import DiffcalcException
from pydantic import BaseModel

#######################################################################################
Expand All @@ -15,18 +14,12 @@ def __init__(self, status_code: int, detail: str):
self.detail = detail


class DiffcalcCoreException(DiffcalcException):
def __init__(self, status_code: int, detail: str):
self.status_code = status_code
self.detail = detail


class DiffcalcExceptionModel(BaseModel):
status_code: int
detail: str


class ErrorCodes(IntEnum):
class ErrorCodesBase(IntEnum):
@classmethod
def all_codes(cls) -> List[int]:
return [val.value for val in cls]
Expand Down
55 changes: 15 additions & 40 deletions src/diffcalc_API/errors/hkl.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,30 @@
from typing import Optional, Tuple, Union

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

from diffcalc_API.errors.definitions import (
ALL_RESPONSES,
DiffcalcAPIException,
ErrorCodes,
ErrorCodesBase,
)


class Codes(ErrorCodes):
CHECK_VALID_MILLER_INDICES = 400
CHECK_VALID_SCAN_BOUNDS = 400
CALCULATE_UB_MATRIX = 400
class ErrorCodes(ErrorCodesBase):
INVALID_MILLER_INDICES = 400
INVALID_SCAN_BOUNDS = 400


responses = {code: ALL_RESPONSES[code] for code in np.unique(Codes.all_codes())}
responses = {code: ALL_RESPONSES[code] for code in np.unique(ErrorCodes.all_codes())}


def check_valid_miller_indices(miller_indices: Tuple[float, float, float]) -> None:
if sum(miller_indices) == 0:
raise DiffcalcAPIException(
status_code=Codes.CHECK_VALID_MILLER_INDICES,
detail="At least one of the hkl indices must be non-zero",
)
return
class InvalidMillerIndicesError(DiffcalcAPIException):
def __init__(self) -> None:
self.detail = "At least one of the hkl indices must be non-zero"
self.status_code = ErrorCodes.INVALID_MILLER_INDICES


def check_valid_scan_bounds(start: float, stop: float, inc: float):
if len(np.arange(start, stop + inc, inc)) == 0:
raise DiffcalcAPIException(
status_code=Codes.CHECK_VALID_SCAN_BOUNDS,
detail=(
f"numpy range cannot be formed from start: {start}"
f" to stop: {stop} in increments of: {inc}"
),
)
return


def calculate_ub_matrix(
hkl: HklCalculation,
first_tag: Optional[Union[int, str]],
second_tag: Optional[Union[int, str]],
) -> None:
try:
hkl.ubcalc.calc_ub(first_tag, second_tag)
except Exception as e:
raise DiffcalcAPIException(
status_code=Codes.CALCULATE_UB_MATRIX,
detail=f"Error calculating UB matrix: {str(e)}",
class InvalidScanBoundsError(DiffcalcAPIException):
def __init__(self, start: float, stop: float, inc: float) -> None:
self.detail = (
f"numpy range cannot be formed from start: {start}"
f" to stop: {stop} in increments of: {inc}"
)
return
self.status_code = ErrorCodes.INVALID_SCAN_BOUNDS
70 changes: 18 additions & 52 deletions src/diffcalc_API/errors/ub.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,37 @@
from typing import Union

import numpy as np
from diffcalc.hkl.calc import HklCalculation
from diffcalc.ub.reference import Orientation, Reflection

from diffcalc_API.config import VECTOR_PROPERTIES
from diffcalc_API.errors.definitions import (
ALL_RESPONSES,
DiffcalcAPIException,
ErrorCodes,
ErrorCodesBase,
)
from diffcalc_API.models.ub import SetLatticeParams


class Codes(ErrorCodes):
CHECK_PARAMS_NOT_EMPTY = 400
GET_REFLECTION = 403
GET_ORIENTATION = 403
CHECK_PROPERTY_IS_VALID = 400
class ErrorCodes(ErrorCodesBase):
INVALID_SET_LATTICE_PARAMS = 400
REFERENCE_RETRIEVAL_ERROR = 403
INVALID_PROPERTY = 400


responses = {code: ALL_RESPONSES[code] for code in np.unique(Codes.all_codes())}
responses = {code: ALL_RESPONSES[code] for code in np.unique(ErrorCodes.all_codes())}


def check_params_not_empty(params: SetLatticeParams) -> None:
non_empty_vars = [var for var, value in params if value is not None]
class InvalidSetLatticeParamsError(DiffcalcAPIException):
def __init__(self):
self.detail = ("please provide lattice parameters in request body",)
self.status_code = ErrorCodes.INVALID_SET_LATTICE_PARAMS

if len(non_empty_vars) == 0:
raise DiffcalcAPIException(
status_code=Codes.CHECK_PARAMS_NOT_EMPTY,
detail="please provide parameters in request body",
)

class ReferenceRetrievalError(DiffcalcAPIException):
def __init__(self, handle: Union[str, int], reference_type: str) -> None:
self.detail = f"cannot retrieve {reference_type} with tag or index {handle}"
self.status_code = ErrorCodes.REFERENCE_RETRIEVAL_ERROR

def get_reflection(hkl: HklCalculation, tag_or_idx: Union[str, int]) -> Reflection:
try:
reflection = hkl.ubcalc.get_reflection(tag_or_idx)
except Exception:
raise DiffcalcAPIException(
status_code=Codes.GET_REFLECTION,
detail=(
"Cannot edit or delete reflection: "
"No reflection with this tag or index"
),
)

return reflection


def get_orientation(hkl: HklCalculation, tag_or_idx: Union[str, int]) -> Orientation:
try:
orientation = hkl.ubcalc.get_orientation(tag_or_idx)
except Exception:
raise DiffcalcAPIException(
status_code=Codes.GET_ORIENTATION,
detail=(
"Cannot edit or delete orientation: "
"No orientation with this tag or index"
),
)

return orientation


def check_property_is_valid(property: str) -> None:
if property not in VECTOR_PROPERTIES:
raise DiffcalcAPIException(
status_code=Codes.CHECK_PROPERTY_IS_VALID,
detail=f"invalid property. Choose one of: {VECTOR_PROPERTIES}",
)
class InvalidPropertyError(DiffcalcAPIException):
def __init__(self):
self.detail = f"invalid property. Choose one of: {VECTOR_PROPERTIES}"
self.status_code = ErrorCodes.INVALID_PROPERTY
13 changes: 10 additions & 3 deletions src/diffcalc_API/routes/ub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from fastapi import APIRouter, Body, Depends, Query, Response

from diffcalc_API.errors.ub import check_params_not_empty, check_property_is_valid
from diffcalc_API.config import VECTOR_PROPERTIES
from diffcalc_API.errors.ub import InvalidPropertyError, InvalidSetLatticeParamsError
from diffcalc_API.examples import ub as examples
from diffcalc_API.models.ub import (
AddOrientationParams,
Expand Down Expand Up @@ -131,9 +132,13 @@ async def set_lattice(
name: str,
params: SetLatticeParams = Body(example=examples.set_lattice),
store: HklCalcStore = Depends(get_store),
_=Depends(check_params_not_empty),
collection: Optional[str] = Query(default=None, example="B07"),
):
non_empty_vars = [var for var, value in params if value is not None]

if len(non_empty_vars) == 0:
raise InvalidSetLatticeParamsError()

await service.set_lattice(name, params, store, collection)
return {
"message": (
Expand All @@ -149,9 +154,11 @@ async def modify_property(
property: str,
target_value: Tuple[float, float, float] = Body(..., example=[1, 0, 0]),
store: HklCalcStore = Depends(get_store),
_=Depends(check_property_is_valid),
collection: Optional[str] = Query(default=None, example="B07"),
):
if property not in VECTOR_PROPERTIES:
raise InvalidPropertyError()

await service.modify_property(name, property, target_value, store, collection)
return {
"message": (
Expand Down
12 changes: 8 additions & 4 deletions src/diffcalc_API/services/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from diffcalc.hkl.constraints import Constraints

from diffcalc_API.config import CONSTRAINTS_WITH_NO_VALUE
from diffcalc_API.errors.constraints import check_constraint_exists
from diffcalc_API.config import ALL_CONSTRAINTS, CONSTRAINTS_WITH_NO_VALUE
from diffcalc_API.errors.constraints import InvalidConstraintError
from diffcalc_API.stores.protocol import HklCalcStore


Expand Down Expand Up @@ -41,7 +41,9 @@ async def remove_constraint(
) -> None:
hklcalc = await store.load(name, collection)

check_constraint_exists(property)
if property not in ALL_CONSTRAINTS:
raise InvalidConstraintError(property)

setattr(hklcalc.constraints, property, None)

await store.save(name, hklcalc, collection)
Expand All @@ -56,7 +58,9 @@ async def set_constraint(
) -> None:
hklcalc = await store.load(name, collection)

check_constraint_exists(property)
if property not in ALL_CONSTRAINTS:
raise InvalidConstraintError(property)

if property in CONSTRAINTS_WITH_NO_VALUE:
value = bool(value)

Expand Down
30 changes: 19 additions & 11 deletions src/diffcalc_API/services/hkl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
import numpy as np
from diffcalc.hkl.geometry import Position

from diffcalc_API.errors.hkl import (
calculate_ub_matrix,
check_valid_miller_indices,
check_valid_scan_bounds,
)
from diffcalc_API.errors.hkl import InvalidMillerIndicesError, InvalidScanBoundsError
from diffcalc_API.stores.protocol import HklCalcStore

PositionType = Tuple[float, float, float]
Expand All @@ -23,7 +19,9 @@ async def lab_position_from_miller_indices(
) -> List[Dict[str, float]]:
hklcalc = await store.load(name, collection)

check_valid_miller_indices(miller_indices)
if all([idx == 0 for idx in miller_indices]):
raise InvalidMillerIndicesError()

all_positions = hklcalc.get_position(*miller_indices, wavelength)

return combine_lab_position_results(all_positions)
Expand Down Expand Up @@ -59,7 +57,9 @@ async def scan_hkl(
results = {}

for h, k, l in product(*axes_values):
check_valid_miller_indices((h, k, l))
if all([idx == 0 for idx in (h, k, l)]):
raise InvalidMillerIndicesError() # what if this goes through 0?

all_positions = hklcalc.get_position(h, k, l, wavelength)
results[f"({h}, {k}, {l})"] = combine_lab_position_results(all_positions)

Expand All @@ -76,7 +76,10 @@ async def scan_wavelength(
collection: Optional[str],
) -> Dict[str, List[Dict[str, float]]]:
hklcalc = await store.load(name, collection)
check_valid_scan_bounds(start, stop, inc)

if len(np.arange(start, stop + inc, inc)) == 0:
raise InvalidScanBoundsError(start, stop, inc)

wavelengths = np.arange(start, stop + inc, inc)
result = {}

Expand All @@ -99,7 +102,10 @@ async def scan_constraint(
collection: Optional[str],
) -> Dict[str, List[Dict[str, float]]]:
hklcalc = await store.load(name, collection)
check_valid_scan_bounds(start, stop, inc)

if len(np.arange(start, stop + inc, inc)) == 0:
raise InvalidScanBoundsError(start, stop, inc)

result = {}
for value in np.arange(start, stop + inc, inc):
setattr(hklcalc, constraint, value)
Expand All @@ -110,7 +116,9 @@ async def scan_constraint(


def generate_axis(start: float, stop: float, inc: float):
check_valid_scan_bounds(start, stop, inc)
if len(np.arange(start, stop + inc, inc)) == 0:
raise InvalidScanBoundsError(start, stop, inc)

return np.arange(start, stop + inc, inc)


Expand All @@ -134,7 +142,7 @@ async def calculate_ub(
) -> str:
hklcalc = await store.load(name, collection)

calculate_ub_matrix(hklcalc, first_tag, second_tag)
hklcalc.ubcalc.calc_ub(first_tag, second_tag)

await store.save(name, hklcalc, collection)
return str(np.round(hklcalc.ubcalc.UB, 6))
Loading