Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Unions #137

Merged
merged 2 commits into from
Nov 30, 2022
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
29 changes: 23 additions & 6 deletions src/diffcalc_api/models/response.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Pydantic models relating to all endpoint responses."""
from typing import Dict, List, Union
from typing import Dict, List

from pydantic import BaseModel

Expand Down Expand Up @@ -46,14 +46,31 @@ class DiffractorAnglesResponse(BaseModel):
payload: List[Dict[str, float]]


class CoordinateResponse(BaseModel):
"""Coordinate response model.
class SphericalResponse(BaseModel):
"""Spherical coordinate response model.

Returns coordinates, in three dimensions, for a given coordinate system.
Supported systems include spherical coordinates, reciprocal and real space.
Returns a payload in spherical coordinates.
"""

payload: Union[SphericalCoordinates, HklModel, XyzModel]
payload: SphericalCoordinates


class ReciprocalSpaceResponse(BaseModel):
"""Reciprocal space coordinate response model.

Returns a payload in reciprocal space (hkl) coordinates.
"""

payload: HklModel


class RealSpaceResponse(BaseModel):
"""Reciprocal space coordinate response model.

Returns a payload in xyz coordinates.
"""

payload: XyzModel


class MiscutResponse(BaseModel):
Expand Down
8 changes: 4 additions & 4 deletions src/diffcalc_api/routes/hkl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from diffcalc_api.errors.hkl import InvalidSolutionBoundsError
from diffcalc_api.models.hkl import SolutionConstraints
from diffcalc_api.models.response import (
CoordinateResponse,
DiffractorAnglesResponse,
ReciprocalSpaceResponse,
ScanResponse,
)
from diffcalc_api.models.ub import HklModel, PositionModel
Expand Down Expand Up @@ -60,7 +60,7 @@ async def lab_position_from_miller_indices(
return DiffractorAnglesResponse(payload=positions)


@router.get("/{name}/position/hkl", response_model=CoordinateResponse)
@router.get("/{name}/position/hkl", response_model=ReciprocalSpaceResponse)
async def miller_indices_from_lab_position(
name: str,
pos: PositionModel = Depends(),
Expand All @@ -78,12 +78,12 @@ async def miller_indices_from_lab_position(
collection: collection within which the hkl object resides.

Returns:
CoordinateResponse containing the miller indices.
ReciprocalSpaceResponse containing the miller indices.
"""
hkl = await service.miller_indices_from_lab_position(
name, pos, wavelength, store, collection
)
return CoordinateResponse(payload=hkl)
return ReciprocalSpaceResponse(payload=hkl)


@router.get("/{name}/scan/hkl", response_model=ScanResponse)
Expand Down
75 changes: 35 additions & 40 deletions src/diffcalc_api/routes/ub.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Endpoints relating to the management of setting up the UB calculation."""

from typing import List, Optional, Union
from typing import List, Optional, cast

from fastapi import APIRouter, Body, Depends, Query

Expand All @@ -12,9 +12,10 @@
from diffcalc_api.examples import ub as examples
from diffcalc_api.models.response import (
ArrayResponse,
CoordinateResponse,
InfoResponse,
MiscutResponse,
ReciprocalSpaceResponse,
SphericalResponse,
StringResponse,
)
from diffcalc_api.models.ub import (
Expand Down Expand Up @@ -611,7 +612,7 @@ async def set_miller_surface_normal(
)


@router.get("/{name}/nphi", response_model=Union[ArrayResponse, InfoResponse])
@router.get("/{name}/nphi", response_model=ArrayResponse)
async def get_lab_reference_vector(
name: str,
store: HklCalcStore = Depends(get_store),
Expand All @@ -625,20 +626,20 @@ async def get_lab_reference_vector(
collection: collection within which the hkl object resides.

Returns:
ArrayResponse with the vector, or
InfoResponse if it doesn't exist
ArrayResponse with the vector. If it doesn't exist, a null vector is returned.

"""
lab_vector: Optional[List[List[float]]] = await service.get_lab_reference_vector(
vector: Optional[List[List[float]]] = await service.get_lab_reference_vector(
name, store, collection
)
if lab_vector is not None:
return ArrayResponse(payload=lab_vector)
else:
return InfoResponse(message="This vector does not exist.")

if vector is None:
return ArrayResponse(payload=[[]])

@router.get("/{name}/nhkl", response_model=Union[ArrayResponse, InfoResponse])
return ArrayResponse(payload=vector)


@router.get("/{name}/nhkl", response_model=ArrayResponse)
async def get_miller_reference_vector(
name: str,
store: HklCalcStore = Depends(get_store),
Expand All @@ -652,20 +653,18 @@ async def get_miller_reference_vector(
collection: collection within which the hkl object resides.

Returns:
ArrayResponse with the vector, or
InfoResponse if it doesn't exist
ArrayResponse with the vector. By default, newly instantiated
Hkl objects always have this vector.

"""
lab_vector: Optional[List[List[float]]] = await service.get_miller_reference_vector(
vector: Optional[List[List[float]]] = await service.get_miller_reference_vector(
name, store, collection
)
if lab_vector is not None:
return ArrayResponse(payload=lab_vector)
else:
return InfoResponse(message="This vector does not exist.")

return ArrayResponse(payload=cast(List[List[float]], vector))

@router.get("/{name}/surface/nphi", response_model=Union[ArrayResponse, InfoResponse])

@router.get("/{name}/surface/nphi", response_model=ArrayResponse)
async def get_lab_surface_normal(
name: str,
store: HklCalcStore = Depends(get_store),
Expand All @@ -679,20 +678,17 @@ async def get_lab_surface_normal(
collection: collection within which the hkl object resides.

Returns:
ArrayResponse with the vector, or
InfoResponse if it doesn't exist
ArrayResponse with the vector. By default, newly instantiated
Hkl objects always have this vector.

"""
lab_vector: Optional[List[List[float]]] = await service.get_lab_surface_normal(
vector: Optional[List[List[float]]] = await service.get_lab_surface_normal(
name, store, collection
)
if lab_vector is not None:
return ArrayResponse(payload=lab_vector)
else:
return InfoResponse(message="This vector does not exist.")
return ArrayResponse(payload=cast(List[List[float]], vector))


@router.get("/{name}/surface/nhkl", response_model=Union[ArrayResponse, InfoResponse])
@router.get("/{name}/surface/nhkl", response_model=ArrayResponse)
async def get_miller_surface_normal(
name: str,
store: HklCalcStore = Depends(get_store),
Expand All @@ -706,25 +702,22 @@ async def get_miller_surface_normal(
collection: collection within which the hkl object resides.

Returns:
ArrayResponse with the vector, or
InfoResponse if it doesn't exist
ArrayResponse with the vector. By default, newly instantiated
Hkl objects always have this vector.

"""
lab_vector: Optional[List[List[float]]] = await service.get_miller_surface_normal(
vector: Optional[List[List[float]]] = await service.get_miller_surface_normal(
name, store, collection
)
if lab_vector is not None:
return ArrayResponse(payload=lab_vector)
else:
return InfoResponse(message="This vector does not exist.")
return ArrayResponse(payload=cast(List[List[float]], vector))


#######################################################################################
# Vector Calculations in HKL Space #
#######################################################################################


@router.get("/{name}/vector", response_model=CoordinateResponse)
@router.get("/{name}/vector", response_model=ReciprocalSpaceResponse)
async def calculate_vector_from_hkl_and_offset(
name: str,
hkl_ref: HklModel = Depends(),
Expand All @@ -747,18 +740,20 @@ async def calculate_vector_from_hkl_and_offset(
collection: collection within which the hkl object resides.

Returns:
CoordinateResponse
ReciprocalSpaceResponse
Containing the calculated reciprocal space vector as h, k, l indices.

"""
vector = await service.calculate_vector_from_hkl_and_offset(
name, hkl_ref, polar_angle, azimuth_angle, store, collection
)

return CoordinateResponse(payload=HklModel(h=vector[0], k=vector[1], l=vector[2]))
return ReciprocalSpaceResponse(
payload=HklModel(h=vector[0], k=vector[1], l=vector[2])
)


@router.get("/{name}/offset", response_model=CoordinateResponse)
@router.get("/{name}/offset", response_model=SphericalResponse)
async def calculate_offset_from_vector_and_hkl(
name: str,
h1: float = Query(..., example=0.0),
Expand Down Expand Up @@ -787,7 +782,7 @@ async def calculate_offset_from_vector_and_hkl(
collection: collection within which the hkl object resides.

Returns:
CoordinateResponse
SphericalResponse
The offset, in spherical coordinates, between the two reciprocal space vectors,
containing the polar angle, azimuth angle and magnitude between them.

Expand All @@ -799,7 +794,7 @@ async def calculate_offset_from_vector_and_hkl(
name, hkl_offset, hkl_ref, store, collection
)

return CoordinateResponse(
return SphericalResponse(
payload=SphericalCoordinates(
polar_angle=vector[0], azimuth_angle=vector[1], magnitude=vector[2]
)
Expand Down
9 changes: 9 additions & 0 deletions tests/test_ubcalc.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,15 @@ def test_get_and_set_reference_vectors_hkl(
)


def test_get_reference_vectors_for_null_vectors():
ubcalc = UBCalculation()
hkl = HklCalculation(ubcalc, Constraints())
client = Client(hkl).client

response = client.get("/ub/test/nphi?collection=B07")
assert literal_eval(response.content.decode())["payload"] == [[]]


def test_calculate_vector_from_hkl_and_offset():
ubcalc = UBCalculation()
ubcalc.UB = np.identity(3)
Expand Down