diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000..167a55d Binary files /dev/null and b/dump.rdb differ diff --git a/src/diffcalc_API/examples/UBCalculation.py b/src/diffcalc_API/examples/UBCalculation.py new file mode 100644 index 0000000..1835138 --- /dev/null +++ b/src/diffcalc_API/examples/UBCalculation.py @@ -0,0 +1,37 @@ +from diffcalc_API.models.UBCalculation import ( + addOrientationParams, + addReflectionParams, + editOrientationParams, + editReflectionParams, + setLatticeParams, +) + +addReflection: addReflectionParams = addReflectionParams( + **{ + "hkl": [0, 0, 1], + "position": [7.31, 0.0, 10.62, 0, 0.0, 0], + "energy": 12.39842, + "tag": "refl1", + } +) + +editReflection: editReflectionParams = editReflectionParams( + **{"energy": 12.45, "tagOrIdx": "refl1"} +) + +addOrientation: addOrientationParams = addOrientationParams( + **{ + "hkl": [0, 1, 0], + "xyz": [0, 1, 0], + "tag": "plane", + } +) + +editOrientation: editOrientationParams = editOrientationParams( + **{ + "hkl": (0, 1, 0), + "tagOrIdx": "plane", + } +) + +setLattice: setLatticeParams = setLatticeParams(**{"a": 4.913, "c": 5.405}) diff --git a/src/diffcalc_API/examples/__init__.py b/src/diffcalc_API/examples/__init__.py new file mode 100644 index 0000000..f18cbe3 --- /dev/null +++ b/src/diffcalc_API/examples/__init__.py @@ -0,0 +1,3 @@ +from diffcalc_API.examples import UBCalculation + +__all__ = ["UBCalculation"] diff --git a/src/diffcalc_API/routes/Constraints.py b/src/diffcalc_API/routes/Constraints.py index b29c0fb..fa95477 100644 --- a/src/diffcalc_API/routes/Constraints.py +++ b/src/diffcalc_API/routes/Constraints.py @@ -1,20 +1,15 @@ from pathlib import Path -from typing import Callable, Dict, Tuple, Union +from typing import Callable, Dict, Union from diffcalc.hkl.calc import HklCalculation -from diffcalc.hkl.constraints import Constraints from fastapi import APIRouter, Body, Depends, Response -from diffcalc_API.config import constraintsWithNoValue -from diffcalc_API.errors.Constraints import check_constraint_exists from diffcalc_API.fileHandling import supplyPersist, unpickleHkl +from diffcalc_API.services import Constraints as service router = APIRouter(prefix="/constraints", tags=["constraints"]) -singleConstraintType = Union[Tuple[str, float], str] - - @router.get("/{name}") async def get_constraints_status( name: str, hklCalc: HklCalculation = Depends(unpickleHkl) @@ -31,12 +26,7 @@ async def set_constraints( hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - booleanConstraints = set(constraintDict.keys()).intersection(constraintsWithNoValue) - for constraint in booleanConstraints: - constraintDict[constraint] = bool(constraintDict[constraint]) - - hklCalc.constraints = Constraints(constraintDict) - persist(hklCalc, name) + service.set_constraints(name, constraintDict, hklCalc, persist) return {"message": f"constraints updated (replaced) for crystal {name}"} @@ -47,9 +37,7 @@ async def remove_constraint( hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - check_constraint_exists(property) - setattr(hklCalc.constraints, property, None) - persist(hklCalc, name) + service.remove_constraint(name, property, hklCalc, persist) return { "message": ( @@ -67,13 +55,7 @@ async def set_constraint( hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - check_constraint_exists(property) - - if property in constraintsWithNoValue: - value = bool(value) - - setattr(hklCalc.constraints, property, value) - persist(hklCalc, name) + service.set_constraint(name, property, value, hklCalc, persist) return { "message": ( diff --git a/src/diffcalc_API/routes/HklCalculation.py b/src/diffcalc_API/routes/HklCalculation.py index e201010..2162f0b 100644 --- a/src/diffcalc_API/routes/HklCalculation.py +++ b/src/diffcalc_API/routes/HklCalculation.py @@ -1,20 +1,16 @@ -from itertools import product from pathlib import Path -from typing import Callable, Dict, List, Optional, Tuple, Union +from typing import Callable, 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, Response -from diffcalc_API.errors.HklCalculation import ( - calculate_UB_matrix, - check_valid_miller_indices, - check_valid_scan_bounds, -) from diffcalc_API.fileHandling import supplyPersist, unpickleHkl +from diffcalc_API.services import HklCalculation as service -router = APIRouter(prefix="/calculate", tags=["hkl"]) +router = APIRouter( + prefix="/calculate", tags=["hkl"], dependencies=[Depends(unpickleHkl)] +) singleConstraintType = Union[Tuple[str, float], str] @@ -29,9 +25,7 @@ async def calculate_UB( hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - calculate_UB_matrix(hklCalc, firstTag, secondTag) - - persist(hklCalc, name) + service.calculate_UB(name, firstTag, secondTag, hklCalc, persist) return Response( content=str(np.round(hklCalc.ubcalc.UB, 6)), media_type="application/text" ) @@ -44,10 +38,11 @@ async def lab_position_from_miller_indices( wavelength: float = Query(..., example=1.0), hklCalc: HklCalculation = Depends(unpickleHkl), ): - check_valid_miller_indices(millerIndices) - allPositions = hklCalc.get_position(*millerIndices, wavelength) + positions = service.lab_position_from_miller_indices( + millerIndices, wavelength, hklCalc + ) - return {"payload": combine_lab_position_results(allPositions)} + return {"payload": positions} @router.get("/{name}/position/hkl") @@ -59,13 +54,8 @@ async def miller_indices_from_lab_position( wavelength: float = Query(..., example=1.0), hklCalc: HklCalculation = Depends(unpickleHkl), ): - hklPosition = hklCalc.get_hkl(Position(*pos), wavelength) - return {"payload": tuple(np.round(hklPosition, 16))} - - -def generate_axis(start: float, stop: float, inc: float): - check_valid_scan_bounds(start, stop, inc) - return np.arange(start, stop + inc, inc) + hkl = service.miller_indices_from_lab_position(pos, wavelength, hklCalc) + return {"payload": hkl} @router.get("/{name}/scan/hkl") @@ -77,19 +67,8 @@ async def scan_hkl( wavelength: float = Query(..., example=1), hklCalc: HklCalculation = Depends(unpickleHkl), ): - valueOfAxes = [ - generate_axis(start[i], stop[i], inc[i]) if inc[i] != 0 else [0] - for i in range(3) - ] - - results = {} - - for h, k, l in product(*valueOfAxes): - check_valid_miller_indices((h, k, l)) - allPositions = hklCalc.get_position(h, k, l, wavelength) - results[f"({h}, {k}, {l})"] = combine_lab_position_results(allPositions) - - return {"payload": results} + scanResults = service.scan_hkl(start, stop, inc, wavelength, hklCalc) + return {"payload": scanResults} @router.get("/{name}/scan/wavelength") @@ -101,15 +80,8 @@ async def scan_wavelength( hkl: positionType = Query(..., example=(1, 0, 1)), hklCalc: HklCalculation = Depends(unpickleHkl), ): - check_valid_scan_bounds(start, stop, inc) - wavelengths = np.arange(start, stop + inc, inc) - result = {} - - for wavelength in wavelengths: - allPositions = hklCalc.get_position(*hkl, wavelength) - result[f"{wavelength}"] = combine_lab_position_results(allPositions) - - return {"payload": result} + scanResults = service.scan_wavelength(start, stop, inc, hkl, hklCalc) + return {"payload": scanResults} @router.get("/{name}/scan/{constraint}") @@ -123,20 +95,8 @@ async def scan_constraint( wavelength: float = Query(..., example=1.0), hklCalc: HklCalculation = Depends(unpickleHkl), ): - check_valid_scan_bounds(start, stop, inc) - result = {} - for value in np.arange(start, stop + inc, inc): - setattr(hklCalc, constraint, value) - allPositions = hklCalc.get_position(*hkl, wavelength) - result[f"{value}"] = combine_lab_position_results(allPositions) - - return {"payload": result} - - -def combine_lab_position_results(positions: List[Tuple[Position, Dict[str, float]]]): - result = [] - - for position in positions: - result.append({**position[0].asdict, **position[1]}) + scanResults = service.scan_constraint( + constraint, start, stop, inc, hkl, wavelength, hklCalc + ) - return result + return {"payload": scanResults} diff --git a/src/diffcalc_API/routes/UBCalculation.py b/src/diffcalc_API/routes/UBCalculation.py index 089db53..765a0e8 100644 --- a/src/diffcalc_API/routes/UBCalculation.py +++ b/src/diffcalc_API/routes/UBCalculation.py @@ -2,15 +2,13 @@ from typing import Callable, Tuple from diffcalc.hkl.calc import HklCalculation -from diffcalc.hkl.geometry import Position from fastapi import APIRouter, Body, Depends, Response from diffcalc_API.errors.UBCalculation import ( check_params_not_empty, check_property_is_valid, - get_orientation, - get_reflection, ) +from diffcalc_API.examples import UBCalculation as examples from diffcalc_API.fileHandling import supplyPersist, unpickleHkl from diffcalc_API.models.UBCalculation import ( addOrientationParams, @@ -20,8 +18,13 @@ editReflectionParams, setLatticeParams, ) +from diffcalc_API.services import UBCalculation as service -router = APIRouter(prefix="/ub", tags=["ub"]) +router = APIRouter( + prefix="/ub", + tags=["ub"], + dependencies=[Depends(unpickleHkl), Depends(supplyPersist)], +) @router.get("/{name}") @@ -32,171 +35,99 @@ async def get_UB_status(name: str, hklCalc: HklCalculation = Depends(unpickleHkl @router.put("/{name}/reflection") async def add_reflection( name: str, - params: addReflectionParams = Body( - ..., - example={ - "hkl": [0, 0, 1], - "position": [7.31, 0.0, 10.62, 0, 0.0, 0], - "energy": 12.39842, - "tag": "refl1", - }, - ), + params: addReflectionParams = Body(..., example=examples.addReflection), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - hklCalc.ubcalc.add_reflection( - params.hkl, - Position(*params.position), - params.energy, - params.tag, - ) - - persist(hklCalc, name) - return { - "message": ( - f"added reflection for UB Calculation of crystal {name}. " - f"Reflist is: {hklCalc.ubcalc.reflist.reflections}" - ) - } + service.add_reflection(name, params, hklCalc, persist) + return {"message": f"added reflection for UB Calculation of crystal {name}"} -@router.put("/{name}/orientation") -async def add_orientation( +@router.patch("/{name}/reflection") +async def edit_reflection( name: str, - params: addOrientationParams = Body( - ..., - example={ - "hkl": [0, 1, 0], - "xyz": [0, 1, 0], - "tag": "plane", - }, - ), + params: editReflectionParams = Body(..., example=examples.editReflection), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - position = Position(*params.position) if params.position else None - - hklCalc.ubcalc.add_orientation( - params.hkl, - params.xyz, - position, - params.tag, - ) - - persist(hklCalc, name) - return {"message": f"added orientation for UB Calculation of crystal {name}"} + service.edit_reflection(name, params, hklCalc, persist) + return { + "message": ( + f"reflection with tag/index {params.tagOrIdx} edited to: " + f"{hklCalc.ubcalc.get_reflection(params.tagOrIdx)}." + ) + } -@router.patch("/{name}/lattice") -async def set_lattice( +@router.delete("/{name}/reflection") +async def delete_reflection( name: str, - params: setLatticeParams = Body(example={"a": 4.913, "c": 5.405}), + params: deleteParams = Body(..., example={"tagOrIdx": "refl1"}), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), - _=Depends(check_params_not_empty), ): - hklCalc.ubcalc.set_lattice(name=name, **params.dict()) - persist(hklCalc, name) - return {"message": f"lattice set for UB calculation of crystal {name}"} + service.delete_reflection(name, params.tagOrIdx, hklCalc, persist) + return {"message": f"reflection with tag/index {params.tagOrIdx} deleted."} -@router.patch("/{name}/reflection") -async def edit_reflection( +@router.put("/{name}/orientation") +async def add_orientation( name: str, - params: editReflectionParams = Body( - ..., - example={ - "energy": 12.45, - "tagOrIdx": "refl1", - }, - ), + params: addOrientationParams = Body(..., example=examples.addOrientation), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - reflection = get_reflection(hklCalc, params.tagOrIdx) - hklCalc.ubcalc.edit_reflection( - params.tagOrIdx, - params.hkl if params.hkl else (reflection.h, reflection.k, reflection.l), - Position(params.position) if params.position else reflection.pos, - params.energy if params.energy else reflection.energy, - params.tagOrIdx if isinstance(params.tagOrIdx, str) else None, - ) - persist(hklCalc, name) - return { - "message": ( - f"reflection edited to: {hklCalc.ubcalc.get_reflection(params.tagOrIdx)}." - ) - } + service.add_orientation(name, params, hklCalc, persist) + return {"message": f"added orientation for UB Calculation of crystal {name}"} @router.patch("/{name}/orientation") async def edit_orientation( name: str, - params: editOrientationParams = Body( - ..., - example={ - "hkl": (0, 1, 0), - "tagOrIdx": "plane", - }, - ), + params: editOrientationParams = Body(..., example=examples.editOrientation), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), ): - orientation = get_orientation(hklCalc, params.tagOrIdx) - - hklCalc.ubcalc.edit_orientation( - params.tagOrIdx, - params.hkl if params.hkl else (orientation.h, orientation.k, orientation.l), - params.xyz if params.xyz else (orientation.x, orientation.y, orientation.z), - Position(params.position) if params.position else orientation.pos, - params.tagOrIdx if isinstance(params.tagOrIdx, str) else None, - ) - persist(hklCalc, name) + service.edit_orientation(name, params, hklCalc, persist) return { "message": ( - f"orientation edited to: {hklCalc.ubcalc.get_orientation(params.tagOrIdx)}." + f"orientation with tag/index {params.tagOrIdx} edited to: " + f"{hklCalc.ubcalc.get_orientation(params.tagOrIdx)}." ) } -@router.patch("/{name}/{property}") -async def modify_property( +@router.delete("/{name}/orientation") +async def delete_orientation( name: str, - property: str, - targetValue: Tuple[float, float, float] = Body(..., example=[1, 0, 0]), + params: deleteParams = Body(..., example={"tagOrIdx": "plane"}), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), - _=Depends(check_property_is_valid), ): - setattr(hklCalc.ubcalc, property, targetValue) - persist(hklCalc, name) - - return {"message": f"{property} set for UB calculation of crystal {name}"} + service.delete_orientation(name, params.tagOrIdx, hklCalc, persist) + return {"message": f"reflection with tag or index {params.tagOrIdx} deleted."} -@router.delete("/{name}/reflection") -async def delete_reflection( +@router.patch("/{name}/lattice") +async def set_lattice( name: str, - params: deleteParams = Body(..., example={"tagOrIdx": "refl1"}), + params: setLatticeParams = Body(example=examples.setLattice), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), + _=Depends(check_params_not_empty), ): - _ = get_reflection(hklCalc, params.tagOrIdx) - hklCalc.ubcalc.del_reflection(params.tagOrIdx) - persist(hklCalc, name) - - return {"message": f"reflection with tag or index {params.tagOrIdx} deleted."} + service.set_lattice(name, params, hklCalc, persist) + return {"message": f"lattice has been set for UB calculation of crystal {name}"} -@router.delete("/{name}/orientation") -async def delete_orientation( +@router.patch("/{name}/{property}") +async def modify_property( name: str, - params: deleteParams = Body(..., example={"tagOrIdx": "plane"}), + property: str, + targetValue: Tuple[float, float, float] = Body(..., example=[1, 0, 0]), hklCalc: HklCalculation = Depends(unpickleHkl), persist: Callable[[HklCalculation, str], Path] = Depends(supplyPersist), + _=Depends(check_property_is_valid), ): - _ = get_orientation(hklCalc, params.tagOrIdx) - hklCalc.ubcalc.del_orientation(params.tagOrIdx) - persist(hklCalc, name) - - return {"message": f"reflection with tag or index {params.tagOrIdx} deleted."} + service.modify_property(name, property, targetValue, hklCalc, persist) + return {"message": f"{property} has been set for UB calculation of crystal {name}"} diff --git a/src/diffcalc_API/server.py b/src/diffcalc_API/server.py index 8669c80..b38ba0a 100644 --- a/src/diffcalc_API/server.py +++ b/src/diffcalc_API/server.py @@ -1,19 +1,19 @@ from diffcalc.util import DiffcalcException from fastapi import FastAPI, Request, responses -from diffcalc_API import errorDefinitions, errors +from diffcalc_API import errorDefinitions +from diffcalc_API.errors.Constraints import responses as responsesConstraints +from diffcalc_API.errors.HklCalculation import responses as responsesHkl +from diffcalc_API.errors.UBCalculation import responses as responsesUb from diffcalc_API.fileHandling import createPickle, deletePickle from . import routes app = FastAPI(responses=errorDefinitions.responses) -app.include_router( - routes.UBCalculation.router, responses=errors.UBCalculation.responses -) -app.include_router(routes.Constraints.router, responses=errors.Constraints.responses) -app.include_router( - routes.HklCalculation.router, responses=errors.HklCalculation.responses -) + +app.include_router(routes.UBCalculation.router, responses=responsesUb) +app.include_router(routes.Constraints.router, responses=responsesConstraints) +app.include_router(routes.HklCalculation.router, responses=responsesHkl) ####################################################################################### # Middleware for Exceptions # @@ -38,6 +38,7 @@ async def http_exception_handler( ) +@app.middleware("http") async def server_exceptions_middleware(request: Request, call_next): try: return await call_next(request) @@ -50,9 +51,6 @@ async def server_exceptions_middleware(request: Request, call_next): ) -app.middleware("http")(server_exceptions_middleware) - - ####################################################################################### # Global Routes # ####################################################################################### diff --git a/src/diffcalc_API/services/Constraints.py b/src/diffcalc_API/services/Constraints.py new file mode 100644 index 0000000..eb9d167 --- /dev/null +++ b/src/diffcalc_API/services/Constraints.py @@ -0,0 +1,52 @@ +from pathlib import Path +from typing import Callable, Dict, Union + +from diffcalc.hkl.calc import HklCalculation +from diffcalc.hkl.constraints import Constraints + +from diffcalc_API.config import constraintsWithNoValue +from diffcalc_API.errors.Constraints import check_constraint_exists + + +def set_constraints( + name: str, + constraintDict: Dict[str, Union[float, bool]], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + booleanConstraints = set(constraintDict.keys()).intersection(constraintsWithNoValue) + for constraint in booleanConstraints: + constraintDict[constraint] = bool(constraintDict[constraint]) + + hklCalc.constraints = Constraints(constraintDict) + persist(hklCalc, name) + return + + +def remove_constraint( + name: str, + property: str, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + check_constraint_exists(property) + setattr(hklCalc.constraints, property, None) + persist(hklCalc, name) + return + + +def set_constraint( + name: str, + property: str, + value: Union[float, bool], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + check_constraint_exists(property) + + if property in constraintsWithNoValue: + value = bool(value) + + setattr(hklCalc.constraints, property, value) + persist(hklCalc, name) + return diff --git a/src/diffcalc_API/services/HklCalculation.py b/src/diffcalc_API/services/HklCalculation.py new file mode 100644 index 0000000..37ac648 --- /dev/null +++ b/src/diffcalc_API/services/HklCalculation.py @@ -0,0 +1,119 @@ +from itertools import product +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 diffcalc_API.errors.HklCalculation import ( + calculate_UB_matrix, + check_valid_miller_indices, + check_valid_scan_bounds, +) + +PositionType = Tuple[float, float, float] + + +def lab_position_from_miller_indices( + millerIndices: Tuple[float, float, float], + wavelength: float, + hklCalc: HklCalculation, +) -> List[Tuple[Position, Dict[str, float]]]: + check_valid_miller_indices(millerIndices) + allPositions = hklCalc.get_position(*millerIndices, wavelength) + + return combine_lab_position_results(allPositions) + + +def miller_indices_from_lab_position( + pos: Tuple[float, float, float, float, float, float], + wavelength: float, + hklCalc: HklCalculation, +): + hklPosition = hklCalc.get_hkl(Position(*pos), wavelength) + return tuple(np.round(hklPosition, 16)) + + +def scan_hkl( + start: PositionType, + stop: PositionType, + inc: PositionType, + wavelength: float, + hklCalc: HklCalculation, +): + valueOfAxes = [ + generate_axis(start[i], stop[i], inc[i]) if inc[i] != 0 else [0] + for i in range(3) + ] + + results = {} + + for h, k, l in product(*valueOfAxes): + check_valid_miller_indices((h, k, l)) + allPositions = hklCalc.get_position(h, k, l, wavelength) + results[f"({h}, {k}, {l})"] = combine_lab_position_results(allPositions) + + return results + + +def scan_wavelength( + start: float, + stop: float, + inc: float, + hkl: PositionType, + hklCalc: HklCalculation, +): + check_valid_scan_bounds(start, stop, inc) + wavelengths = np.arange(start, stop + inc, inc) + result = {} + + for wavelength in wavelengths: + allPositions = hklCalc.get_position(*hkl, wavelength) + result[f"{wavelength}"] = combine_lab_position_results(allPositions) + + return result + + +def scan_constraint( + constraint: str, + start: float, + stop: float, + inc: float, + hkl: PositionType, + wavelength: float, + hklCalc: HklCalculation, +): + check_valid_scan_bounds(start, stop, inc) + result = {} + for value in np.arange(start, stop + inc, inc): + setattr(hklCalc, constraint, value) + allPositions = hklCalc.get_position(*hkl, wavelength) + result[f"{value}"] = combine_lab_position_results(allPositions) + + return result + + +def generate_axis(start: float, stop: float, inc: float): + check_valid_scan_bounds(start, stop, inc) + return np.arange(start, stop + inc, inc) + + +def combine_lab_position_results(positions: List[Tuple[Position, Dict[str, float]]]): + result = [] + + for position in positions: + result.append({**position[0].asdict, **position[1]}) + + return result + + +def calculate_UB( + name: str, + firstTag: Optional[Union[int, str]], + secondTag: Optional[Union[int, str]], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + calculate_UB_matrix(hklCalc, firstTag, secondTag) + persist(hklCalc, name) diff --git a/src/diffcalc_API/services/UBCalculation.py b/src/diffcalc_API/services/UBCalculation.py new file mode 100644 index 0000000..f0ca2ca --- /dev/null +++ b/src/diffcalc_API/services/UBCalculation.py @@ -0,0 +1,132 @@ +from pathlib import Path +from typing import Callable, Tuple, Union + +from diffcalc.hkl.calc import HklCalculation +from diffcalc.hkl.geometry import Position + +from diffcalc_API.errors.UBCalculation import get_orientation, get_reflection +from diffcalc_API.models.UBCalculation import ( + addOrientationParams, + addReflectionParams, + editOrientationParams, + editReflectionParams, + setLatticeParams, +) + + +def add_reflection( + name: str, + params: addReflectionParams, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + hklCalc.ubcalc.add_reflection( + params.hkl, + Position(*params.position), + params.energy, + params.tag, + ) + + persist(hklCalc, name) + return + + +def edit_reflection( + name: str, + params: editReflectionParams, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + reflection = get_reflection(hklCalc, params.tagOrIdx) + + hklCalc.ubcalc.edit_reflection( + params.tagOrIdx, + params.hkl if params.hkl else (reflection.h, reflection.k, reflection.l), + Position(params.position) if params.position else reflection.pos, + params.energy if params.energy else reflection.energy, + params.tagOrIdx if isinstance(params.tagOrIdx, str) else None, + ) + persist(hklCalc, name) + return + + +def delete_reflection( + name: str, + tagOrIdx: Union[str, int], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + _ = get_reflection(hklCalc, tagOrIdx) + hklCalc.ubcalc.del_reflection(tagOrIdx) + persist(hklCalc, name) + return + + +def add_orientation( + name: str, + params: addOrientationParams, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + position = Position(*params.position) if params.position else None + + hklCalc.ubcalc.add_orientation( + params.hkl, + params.xyz, + position, + params.tag, + ) + + persist(hklCalc, name) + return + + +def edit_orientation( + name: str, + params: editOrientationParams, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + orientation = get_orientation(hklCalc, params.tagOrIdx) + + hklCalc.ubcalc.edit_orientation( + params.tagOrIdx, + params.hkl if params.hkl else (orientation.h, orientation.k, orientation.l), + params.xyz if params.xyz else (orientation.x, orientation.y, orientation.z), + Position(params.position) if params.position else orientation.pos, + params.tagOrIdx if isinstance(params.tagOrIdx, str) else None, + ) + persist(hklCalc, name) + return + + +def delete_orientation( + name: str, + tagOrIdx: Union[str, int], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + _ = get_orientation(hklCalc, tagOrIdx) + hklCalc.ubcalc.del_orientation(tagOrIdx) + persist(hklCalc, name) + + +def set_lattice( + name: str, + params: setLatticeParams, + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + hklCalc.ubcalc.set_lattice(name=name, **params.dict()) + persist(hklCalc, name) + + +def modify_property( + name: str, + property: str, + targetValue: Tuple[float, float, float], + hklCalc: HklCalculation, + persist: Callable[[HklCalculation, str], Path], +): + setattr(hklCalc.ubcalc, property, targetValue) + persist(hklCalc, name) diff --git a/src/diffcalc_API/services/__init__.py b/src/diffcalc_API/services/__init__.py new file mode 100644 index 0000000..132d9e5 --- /dev/null +++ b/src/diffcalc_API/services/__init__.py @@ -0,0 +1,3 @@ +from diffcalc_API.services import Constraints, HklCalculation, UBCalculation + +__all__ = ["UBCalculation", "HklCalculation", "Constraints"]