Skip to content

Commit

Permalink
fix find_image_atoms() for non-cuboid lattices
Browse files Browse the repository at this point in the history
use shear matrix to render lattice (fixes rendering lattice as parallelepiped, i.e. when show_cell = 'surface')
use <Bond> + <T.ConeGeometry> to render lattice vectors
  • Loading branch information
janosh committed Jul 16, 2023
1 parent d4dce4b commit 9138582
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 116 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"jsdom": "^22.1.0",
"mdsvex": "^0.11.0",
"mdsvexamples": "^0.3.3",
"prettier": "^3.0.0",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.1",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex-svelte": "^1.2.0",
Expand Down
9 changes: 5 additions & 4 deletions src/lib/InfoCard.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<script lang="ts">
import { pretty_num } from '$lib'
import type { PropertyOrigin } from '$types'
export let data: {
title: string
value: string | number | number[]
value?: string | number | number[] | null | PropertyOrigin
unit?: string
fmt?: string
condition?: boolean
condition?: boolean | number | null
tooltip?: string
}[] = []
export let title: string = ``
Expand All @@ -26,7 +27,7 @@
</slot>
</h2>
{/if}
{#each data as { title, value, unit, fmt = default_fmt, tooltip }}
{#each data.filter((itm) => (!(`condition` in itm) || itm?.condition) && ![undefined, null].includes(itm.value)) as { title, value, unit, fmt = default_fmt, tooltip }}
<div>
<span class="title" {title}>
{@html title}
Expand All @@ -53,7 +54,7 @@
border-radius: var(--ic-radius, 3pt);
padding: var(--ic-padding, 10pt 12pt);
margin: var(--ic-margin, 1em 0);
gap: var(--ic-gap, 10pt 1em);
gap: var(--ic-gap, 10pt 5%);
background-color: var(--ic-bg, rgba(255, 255, 255, 0.1));
font-size: var(--ic-font-size);
width: var(--ic-width);
Expand Down
48 changes: 33 additions & 15 deletions src/lib/material/MaterialCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,46 @@
value: material.origins,
condition: material.origins?.length,
},
].filter((itm) => itm?.condition ?? true)
{
title: `Is magnetic`,
value: `${material.is_magnetic ? `yes` : `no`} ${
material.is_magnetic ? `(${material.total_magnetization})` : ``
}`,
},
{
title: `Voigt bulk modulus`,
value: material.k_voigt,
unit: `GPa`,
},
{
title: `Voig shear modulus`,
value: material.g_voigt,
unit: `GPa`,
},
{ title: `Refractive index`, value: material.n },
{ title: `Ordering`, value: material.ordering },
]
</script>

<InfoCard {data} {...$$restProps} />

<details>
<summary>Related materials IDs</summary>
{#if material.task_ids?.length}
<p>
Task IDs: {#each material.task_ids as id}
<a href="https://materialsproject.org/tasks/{id}">{id}</a>
{/each}
</p>
{/if}
{#if material.database_IDs.icsd?.length}

<p>
ICSD IDs: {#each material.database_IDs.icsd as id}
<a href="https://ccdc.cam.ac.uk/structures/Search?Ccdcid={id}&DatabaseToSearch=ICSD">{id}</a>
{/each}
</p>
{/if}
<p>
Task IDs: {#each material.task_ids as id}
<a href="https://materialsproject.org/tasks/{id}">{id}</a>
{/each}
</p>
{/if}
{#if material.database_IDs?.icsd?.length}
<p>
ICSD IDs: {#each material.database_IDs.icsd as id}
{@const href = `https://ccdc.cam.ac.uk/structures/Search?Ccdcid=${id}&DatabaseToSearch=ICSD`}
<a {href}>{id}</a>
{/each}
</p>
{/if}
</details>

<p class="warning">
Expand Down
4 changes: 2 additions & 2 deletions src/lib/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ export function norm(vec: NdVector): number {
return Math.sqrt(vec.reduce((acc, val) => acc + val ** 2, 0))
}

export function scale(vec: NdVector, factor: number): NdVector {
export function scale<T extends Vector>(vec: T, factor: number): T {
return vec.map((val) => val * factor)
}

export function euclidean_dist(vec1: Vector, vec2: Vector): number {
return norm(add(vec1, scale(vec2, -1)))
}

export function add(...vecs: NdVector[]): NdVector {
export function add<T extends Vector>(...vecs: T[]): T {
// add up any number of same-length vectors
const result = vecs[0].slice()
for (const vec of vecs.slice(1)) {
Expand Down
7 changes: 4 additions & 3 deletions src/lib/structure/Bond.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
import type { Vector } from '$lib'
import { Instance } from '@threlte/extras'
import { Euler, Quaternion, Vector3 } from 'three'
export let from: [number, number, number]
export let to: [number, number, number]
export let from: Vector = [0, 0, 0]
export let to: Vector
export let offset: number = 0
export let radius: number = 0.1
export let color: string = `white`
Expand All @@ -19,7 +20,7 @@
// length of the bond
const height = delta_vec.length()
// calculate position
let position: [number, number, number]
let position: Vector
if (offset === 0) {
position = from_vec.clone().add(delta_vec.multiplyScalar(0.5)).toArray()
} else {
Expand Down
81 changes: 35 additions & 46 deletions src/lib/structure/Lattice.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<script lang="ts">
import { add, type Vector } from '$lib'
import { add, scale, type Vector } from '$lib'
import { T } from '@threlte/core'
import { BufferGeometry, Vector3 } from 'three'
import { InstancedMesh } from '@threlte/extras'
import { BoxGeometry, Matrix4, Vector3 } from 'three'
import Bond from './Bond.svelte'
export let matrix: [Vector, Vector, Vector]
export let show_cell: 'surface' | 'wireframe' | null = `wireframe`
Expand All @@ -19,57 +21,44 @@
// lattice vector origin (all arrows start from this point)
export let vector_origin: Vector = [-1, -1, -1]
$: [vec_a, vec_b, vec_c] = matrix
const origin = [0, 0, 0]
$: points = [
origin,
add(origin, vec_a),
origin,
add(origin, vec_b),
origin,
add(origin, vec_c),
add(origin, vec_a),
add(origin, vec_a, vec_b),
add(origin, vec_a),
add(origin, vec_a, vec_c),
add(origin, vec_b),
add(origin, vec_b, vec_a),
add(origin, vec_b),
add(origin, vec_b, vec_c),
add(origin, vec_c),
add(origin, vec_c, vec_a),
add(origin, vec_c),
add(origin, vec_c, vec_b),
add(origin, vec_a, vec_b),
add(origin, vec_a, vec_b, vec_c),
add(origin, vec_a, vec_c),
add(origin, vec_a, vec_b, vec_c),
add(origin, vec_b, vec_c),
add(origin, vec_a, vec_b, vec_c),
]
$: geometry = new BoxGeometry(1, 1, 1)
$: shear_matrix = new Matrix4().makeBasis(
...matrix.map((vec) => new Vector3(...vec, 0))
)
$: geometry.applyMatrix4(shear_matrix)
$: lattice_center = scale(add(...matrix), 0.5)
</script>

{#if show_cell}
<T.LineSegments
geometry={new BufferGeometry().setFromPoints(points.map((p) => new Vector3(...p)))}
>
<T.LineBasicMaterial
<T.Mesh {geometry} position={lattice_center}>
<T.MeshBasicMaterial
color={cell_color}
opacity={cell_opacity}
linewidth={cell_line_width}
transparent={cell_opacity !== undefined}
wireframe={show_cell === `wireframe`}
line_width={cell_line_width}
/>
</T.LineSegments>
</T.Mesh>
{/if}

{#if show_vectors}
{#each matrix as vec, idx}
{@const [x, y, z] = vec ?? []}
<T.Group position={vector_origin}>
<T.ArrowHelper
args={[{ x, y, z }, { x: 0, y: 0, z: 0 }, 6, vector_colors[idx], 1, 1, 1]}
/>
</T.Group>
{/each}
<T.Group position={vector_origin}>
<InstancedMesh>
<T.CylinderGeometry args={[0.1, 0.1, 1, 16]} />

<T.MeshStandardMaterial />
{#each matrix as vec, idx}
<Bond to={scale(vec, 0.5)} color={vector_colors[idx]} />
{/each}
</InstancedMesh>
<InstancedMesh>
<T.MeshStandardMaterial />
<!-- [thickness, length, radial segments] -->
<T.ConeGeometry args={[0.25, 0.12, 16]} />

{#each matrix as vec, idx}
<Bond to={vec} color={vector_colors[idx]} />
{/each}
</InstancedMesh>
</T.Group>
{/if}
34 changes: 16 additions & 18 deletions src/lib/structure/Structure.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<script lang="ts">
import { element_color_schemes } from '$lib/colors'
import { element_colors } from '$lib/stores'
import { Canvas } from '@threlte/core'
import { Tooltip } from 'svelte-zoo'
import type { ElementSymbol } from '..'
import { download } from '../api'
import type { PymatgenStructure } from '../structure'
import type { ElementSymbol, PymatgenStructure, Vector } from '$lib'
import {
add,
alphabetical_formula,
get_elem_amounts,
scale,
symmetrize_structure,
} from '../structure'
} from '$lib'
import { download } from '$lib/api'
import { element_color_schemes } from '$lib/colors'
import { element_colors } from '$lib/stores'
import { Canvas } from '@threlte/core'
import { Tooltip } from 'svelte-zoo'
import StructureLegend from './StructureLegend.svelte'
import StructureScene from './StructureScene.svelte'
Expand All @@ -22,7 +23,7 @@
// determined by the atomic radius of the element
export let same_size_atoms: boolean = true
// initial camera position from which to render the scene
export let camera_position: [number, number, number] = [10, 10, 10]
export let camera_position: Vector = [10, 10, 10]
// zoom level of the camera
export let initial_zoom: number | undefined = undefined
// auto rotate speed. set to 0 to disable auto rotation.
Expand All @@ -44,7 +45,7 @@
export let show_bonds: boolean = true
export let bond_radius: number | undefined = undefined
export let show_cell: 'surface' | 'wireframe' | null = `wireframe`
export let cell_opacity: number | undefined = 0.15
export let cell_opacity: number | undefined = 0.5
export let cell_line_width: number = 1
export let wrapper: HTMLDivElement | undefined = undefined
// the control panel DOM element
Expand Down Expand Up @@ -84,11 +85,11 @@
}
}
$: ({ a, b, c } = structure?.lattice ?? { a: 0, b: 0, c: 0 })
$: {
// set camera position based on structure size
const scale = initial_zoom ?? 1000 / Math.min(width, height)
camera_position = [scale * a, scale * b, scale * c]
const factor = initial_zoom ?? 700 / Math.min(width, height)
const [vec_a, vec_b, vec_c] = structure?.lattice?.matrix ?? [[], [], []]
camera_position = scale(add(vec_a, vec_b, vec_c), factor)
}
const on_window_click =
(node: (HTMLElement | null)[], cb: () => void) => (event: MouseEvent) => {
Expand Down Expand Up @@ -303,16 +304,13 @@
<button type="button" on:click={download_json} title={save_json_btn_text}>
{save_json_btn_text}
</button>
<button type=button on:click={download_png} title={save_png_btn_text}>
<button type="button" on:click={download_png} title={save_png_btn_text}>
{save_png_btn_text}
</button>
</span>

</dialog>

<Canvas rendererParameters={{
preserveDrawingBuffer: true
}}>
<Canvas rendererParameters={{ preserveDrawingBuffer: true }}>
<StructureScene
structure={show_image_atoms ? symmetrize_structure(structure) : structure}
{show_atoms}
Expand Down
13 changes: 12 additions & 1 deletion src/lib/structure/StructureScene.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// determined by the atomic radius of the element
export let same_size_atoms: boolean = true
// initial camera position from which to render the scene
export let camera_position: [number, number, number] = [10, 10, 10]
export let camera_position: Vector = [10, 10, 10]
// zoom level of the camera
export let orbit_controls: OrbitControls | undefined = undefined
export let max_zoom: number | undefined = undefined
Expand Down Expand Up @@ -117,6 +117,17 @@
/>
{/each}
</InstancedMesh>
<!-- TODO find a performant way of rendering labels for each site -->
<!-- {#each structure.sites as site, idx}
{@const { species, xyz } = site}
{@const elem = species[0].element}
{#if $$slots[`atom-label`]}
<HTML center as="div">
<slot name="atom-label" {elem} {xyz} {species} />
</HTML>
{/if}
{/each} -->
{/if}

{#if show_bonds}
Expand Down
Loading

0 comments on commit 9138582

Please sign in to comment.