Search Blogs

Blurbs

Your Blog Page

This is a collection of text and code snippets, thoughts, and blurbs that didn't quite make it as posts but wanted to collect them somewhere.


Origin of the term analog in computing

I was confused about the term "analog" in electronics and where it originates from with regard to the concept of signals and data. It was chosen because a signal or data can be comparable to continuously variable physical quantities. This is in contrast to digital systems, where signals or data are represented by discrete numerical values. Looking at the etymology of the word, "analog" comes from the Greek word "analogos," meaning "proportionate."

The first electronic devices were analog, as they operated by directly manipulating continuous signals. This allowed them to mimic or be analogous to the physical phenomena they were designed to measure, process, or transmit. For example, the voltage across a resistor in an electric circuit could be used to represent the temperature, with changes in voltage corresponding directly to changes in temperature. Hence, voltage signal is analogous to temperature.

Attention as a Form of message passing
  • Transformers: In the Transformer architecture, the attention mechanism allows each token in the sequence to directly "attend" to every other token, essentially forming a fully connected graph where nodes represent tokens, and edges represent the attention weights between tokens. This can be viewed as a form of message passing where information (or messages) from all tokens are aggregated at each token according to the attention weights. The multi-head attention further enriches this process by allowing multiple relationships (or message types) to be learned and aggregated in parallel.
  • Similarity to Graphs: This process is reminiscent of how information is propagated in graphs, especially in GNNs, where nodes aggregate information from their neighbors. The key difference lies in the structure of the graph. In traditional GNNs, the graph's structure is typically determined by the data (e.g., molecular structure) and is not fully connected. In contrast, the Transformer treats sequences as fully connected graphs, at least in the attention mechanism.
Message Passing in GNN
The first thing you should be told is a graph is essentially defined by adjacency matrix. This means its all just Linear Algebra. The features of a GNN can be tied to the diagonal (nodes) and off-diagonal (edges) elements. Therefore, message passing in GNN with averaging aggregation is nothing more than taking the matrix products: D12AD12x. Here D is the degree matrix, which is diagonal with elements Dii=i,jAij and normalizes the adjacency. For convolution over the features just stick a weight matrix W between. Per usually domain people use language to make things sound more complicated.
Materials Project Rest API Julia seed
Its pretty reguarly I pull from the materials project. The recommend interface is with the python package, but they have a full fledge REST API so its easy to implement in Julia. Here is my seed:
using HTTP, JSON
"""
abstract type MaterialsProjectQuery end
An abstract type representing a query to the Materials Project database.
"""
abstract type MaterialsProjectQuery end
"""
struct MaterialIDs <: MaterialsProjectQuery
id::String
query::String
MaterialIDs(ids::Union{String,Vector{String}})
A concrete type for querying materials by their IDs.
# Fields
- `id::String`: A single material ID or a comma-separated list of material IDs.
- `query::String`: The constructed query string for the material IDs.
# Constructor
- `MaterialIDs(ids::Union{String,Vector{String}})`: Create a new `MaterialIDs` object from a single ID or a vector of IDs.
"""
struct MaterialIDs <: MaterialsProjectQuery
id::String
query::String
MaterialIDs(ids::Union{String,Vector{String}}) = begin
search = isa(ids, Vector) ? join(ids, ",") : ids
query = "?material_ids=$(search)"
new(search,query)
end
end
"""
struct Formulas <: MaterialsProjectQuery
formula::String
query::String
Formulas(formulas::Union{String,Vector{String}})
A concrete type for querying materials by their formulas.
# Fields
- `formula::String`: A single formula or a comma-separated list of formulas.
- `query::String`: The constructed query string for the formulas.
# Constructor
- `Formulas(formulas::Union{String,Vector{String}})`: Create a new `Formulas` object from a single formula or a vector of formulas.
"""
struct Formulas <: MaterialsProjectQuery
formula::String
query::String
Formulas(formulas::Union{String,Vector{String}}) = begin
search = isa(formulas, Vector) ? join(formulas, ",") : formulas
query = "?formula=$(search)"
new(search,query)
end
end
"""
struct Elements <: MaterialsProjectQuery
elements::String
query::String
Elements(elements::Union{String,Vector{String}})
A concrete type for querying materials by their elements.
# Fields
- `elements::String`: A single element or a comma-separated list of elements.
- `query::String`: The constructed query string for the elements.
# Constructor
- `Elements(elements::Union{String,Vector{String}})`: Create a new `Elements` object from a single element or a vector of elements.
"""
struct Elements <: MaterialsProjectQuery
elements::String
query::String
Elements(elements::Union{String,Vector{String}}) = begin
search = isa(elements, Vector) ? join(elements, ",") : elements
query = "?elements=$(search)"
new(search,query)
end
end
"""
struct Spacegroup <: MaterialsProjectQuery
number::Int
query::String
Spacegroup(spacegroup::Int)
A concrete type for querying materials by their spacegroup number.
# Fields
- `number::Int`: The spacegroup number.
- `query::String`: The constructed query string for the spacegroup number.
# Constructor
- `Spacegroup(spacegroup::Int)`: Create a new `Spacegroup` object from a spacegroup number.
"""
struct Spacegroup <: MaterialsProjectQuery
number::Int
query::String
Spacegroup(spacegroup::Int) = begin
query = "?spacegroup_number=$(spacegroup)"
new(spacegroup,query)
end
end
"""
struct MultiQuery <: MaterialsProjectQuery
query::String
A concrete type for handling multiple query conditions.
# Fields
- `query::String`: The constructed query string combining multiple conditions.
"""
struct MultiQuery <: MaterialsProjectQuery
query::String
end
Base.join(q1::T,q2::S) where {T<:MaterialsProjectQuery, S<:MaterialsProjectQuery} =
begin
q2mod = strip(q2.query,'?')
query = join([q1.query,q2mod],"&")
MultiQuery(query)
end
"""
get_mp(qtype::MaterialsProjectQuery,
api_key::String,
endpoint="materials/summary",
all_fields=true)
Fetch data from the Materials Project API.
# Arguments
- `qtype::MaterialsProjectQuery`: A query type instance (e.g., `MaterialIDs`, `Formulas`, `Elements`, `Spacegroup`, `MultiQuery`).
- `api_key::String`: The API key for accessing the Materials Project API.
- `endpoint::String`: The API endpoint to query. Default is `"materials/summary"`.
- `all_fields::Bool`: Whether to fetch all fields in the query. Default is `true`.
# Returns
- A dictionary containing the response data if the query is successful.
- `nothing` if the query fails or if the API key is empty.
# Examples
```julia
# Query by material IDs
get_mp(MaterialIDs(["mp-1234", "mp-5678"]), "your_api_key")
# Query by formulas
get_mp(Formulas(["WC", "WC2", "W2C"]), "your_api_key")
# Query by elements
get_mp(Elements(["Fe", "O"]), "your_api_key")
# Query by spacegroup number
get_mp(Spacegroup(225), "your_api_key")
# Query by multiple
get_mp(join(Formulas(["WC","WC2","W2C"],Spacegroup(60))),"your_api_key")
```
"""
function get_mp(qtype::MaterialsProjectQuery,
api_key::String,
endpoint="materials/summary",
all_fields=true)
if isempty(api_key)
@error "Materials Project API key is empty!"
return nothing
end
base_url = "https://api.materialsproject.org"
query = join([qtype.query,"_all_fields=$(all_fields)"],"&")
query_url = joinpath([base_url, endpoint, query])
headers = ["accept" => "application/json", "X-API-KEY" => api_key]
response = HTTP.get(query_url,headers,status_exception=false)
# Successful response, parse and return the data
if response.status >= 200 && response.status < 300
data = JSON.parse(String(response.body))
if isempty(data["data"])
@error "Materials Project data is empty!"
end
return data
else
# Response indicates an error, return nothing
@error "Failed query with:" response.status
end
end
Generating coherent (hkl) interfaces
If you need to generate all the compatible crystallogrphic (hkl) pairs for a substrate and film, this might be a useful utility function for you. Note it doesn't perform any relaxation.
from pymatgen.core.structure import Structure
from pymatgen.analysis.interfaces import CoherentInterfaceBuilder
from pymatgen.core.surface import get_symmetrically_distinct_miller_indices
from pymatgen.io.ase import AseAtomsAdaptor
from ase.atoms import Atoms
from typing import List
from joblib import Parallel, delayed
import warnings
def generate_interfaces(
substrate: Structure,
film: Structure,
max_sub_miller_index: int = 1,
max_film_miller_index: int = 2,
interface_thickness: float = 1.5,
vacuum_over_film: float = 0.0,
film_thickness: int = 3,
sub_thickness: int = 5,
in_layers: bool = True
) -> List[Atoms]:
"""
In parallel, generate all geometrically suitable (hkl) interfaces
between a substrate and a film.
Parameters:
substrate (Structure): The `pymatgen` structure of the substrate material.
film (Structure): The `pymatgen` structure of the film material.
max_sub_miller_index (int): Maximum Miller index for the substrate surfaces.
max_film_miller_index (int): Maximum Miller index for the film surfaces.
interface_thickness (float): Thickness of the interface gap in angstroms.
vacuum_over_film (float): Thickness of vacuum above the film in angstroms.
film_thickness (int): Film thickness in unit layers or angstroms.
sub_thickness (int): Substrate thickness in unit layers or angstroms.
in_layers (bool): Whether the thickness parameters are in unit layers.
Returns:
List[Atoms]: A list of ASE Atoms objects representing the generated interfaces.
"""
# Surpress all DeprecationWarnings from pymatgen/spglib
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
sub_miller = get_symmetrically_distinct_miller_indices(substrate, max_sub_miller_index)
film_miller = get_symmetrically_distinct_miller_indices(film, max_film_miller_index)
def process_pair(sub_hkl: tuple, film_hkl: tuple) -> List[Atoms]:
local_interfaces = []
builder = CoherentInterfaceBuilder(
substrate_structure=substrate,
film_structure=film,
film_miller=film_hkl,
substrate_miller=sub_hkl
)
for termination in builder.terminations:
interface_gen = builder.get_interfaces(
termination=termination,
gap=interface_thickness,
vacuum_over_film=vacuum_over_film,
film_thickness=film_thickness,
substrate_thickness=sub_thickness,
in_layers=in_layers
)
for interface in interface_gen:
ase_atoms = AseAtomsAdaptor.get_atoms(interface, msonable=False)
ase_atoms.info['substrate_hkl'] = sub_hkl
ase_atoms.info['film_hkl'] = film_hkl
ase_atoms.info['strain'] = interface.interface_properties.get('strain')
ase_atoms.info['von_mises'] = interface.interface_properties.get('von_mises')
ase_atoms.wrap() # Ensure periodic boundary conditions are visualized correctly
local_interfaces.append(ase_atoms)
return local_interfaces
interfaces = Parallel(n_jobs=-1)(
delayed(process_pair)(sub_hkl, film_hkl) for sub_hkl in sub_miller for film_hkl in film_miller
)
return [item for sublist in interfaces for item in sublist]

Bringuier, S., Blurbs, Dirac's Student, (2024). Retrieved from https://www.diracs-student.blog/p/blurbs.html


Reuse and Attribution

No comments:

Post a Comment

Please refrain from using ad hominem attacks, profanity, slander, or any similar sentiment in your comments. Let's keep the discussion respectful and constructive.