Tutorial 2: Phase analysis with tree search#
Dara is equipped with a parallelized tree search algorithm to identify possible phases present in a given XRD pattern.
In this tutorial, we will try to identify the phases in one experimental solid-state
reaction sample between GeO2 and ZnO.
You can download this tutorial project from here.
%pip install ipywidgets nbformat
from pathlib import Path
from dara import search_phases
pattern_path = "tutorial_data/GeO2-ZnO_700C_60min.xrdml"
# three elements are present in the sample
chemical_system = "Ge-O-Zn"
Step 1: Prepare reference phases#
Dara pre-builds an index of all the unique and low-energy phases in ICSD and COD databases. It also implements a method to download CIF structures from COD data server so that there is no need to obtain the offline database.
Before every search, we will need to gather all the reference phases in the chemical
system for the search algorithm. Dara provides ICSDDatabase and CODDatabase to do
the filtering.
In this example, we will use CODDatabase to download all the phases in the chemical system of Ge-O-Zn.
from dara.structure_db import CODDatabase
# The COD database contains methods to filter phases in the chemical system
cod_database = CODDatabase()
# gather reference phases and save them to a directory called "cifs"
all_icsd_ids = cod_database.get_cifs_by_chemsys(chemical_system, dest_dir="cifs")
2026-07-31 17:10:34,839 WARNING dara.structure_db Local copy of database not found. Attempting to download structures...
Failed to download 9007435: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1537875: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 2104024: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1525835: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1536063: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1525833: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 8000212: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1526227: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 2300365: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 9006858: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 1533322: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 9007477: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Failed to download 4517837: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
---------------------------------------------------------------------------
ConnectionResetError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:788, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
787 # Make the request on the HTTPConnection object
--> 788 response = self._make_request(
789 conn,
790 method,
791 url,
792 timeout=timeout_obj,
793 body=body,
794 headers=headers,
795 chunked=chunked,
796 retries=retries,
797 response_conn=response_conn,
798 preload_content=preload_content,
799 decode_content=decode_content,
800 **response_kw,
801 )
803 # Everything went great!
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:488, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
487 new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 488 raise new_e
490 # conn.request() calls http.client.*.request, not the method in
491 # urllib3.request. It also calls makefile (recv) on the socket.
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:464, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
463 try:
--> 464 self._validate_conn(conn)
465 except (SocketTimeout, BaseSSLError) as e:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:1106, in HTTPSConnectionPool._validate_conn(self, conn)
1105 if conn.is_closed:
-> 1106 conn.connect()
1108 # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connection.py:796, in HTTPSConnection.connect(self)
794 server_hostname_rm_dot = server_hostname.rstrip(".")
--> 796 sock_and_verified = _ssl_wrap_socket_and_match_hostname(
797 sock=sock,
798 cert_reqs=self.cert_reqs,
799 ssl_version=self.ssl_version,
800 ssl_minimum_version=self.ssl_minimum_version,
801 ssl_maximum_version=self.ssl_maximum_version,
802 ca_certs=self.ca_certs,
803 ca_cert_dir=self.ca_cert_dir,
804 ca_cert_data=self.ca_cert_data,
805 cert_file=self.cert_file,
806 key_file=self.key_file,
807 key_password=self.key_password,
808 server_hostname=server_hostname_rm_dot,
809 ssl_context=self.ssl_context,
810 tls_in_tls=tls_in_tls,
811 assert_hostname=self.assert_hostname,
812 assert_fingerprint=self.assert_fingerprint,
813 )
814 self.sock = sock_and_verified.socket
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connection.py:975, in _ssl_wrap_socket_and_match_hostname(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)
973 server_hostname = normalized
--> 975 ssl_sock = ssl_wrap_socket(
976 sock=sock,
977 keyfile=key_file,
978 certfile=cert_file,
979 key_password=key_password,
980 ca_certs=ca_certs,
981 ca_cert_dir=ca_cert_dir,
982 ca_cert_data=ca_cert_data,
983 server_hostname=server_hostname,
984 ssl_context=context,
985 tls_in_tls=tls_in_tls,
986 )
988 try:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/ssl_.py:433, in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)
431 context.set_alpn_protocols(ALPN_PROTOCOLS)
--> 433 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
434 return ssl_sock
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/ssl_.py:477, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
475 return SSLTransport(sock, ssl_context, server_hostname)
--> 477 return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:455, in SSLContext.wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
449 def wrap_socket(self, sock, server_side=False,
450 do_handshake_on_connect=True,
451 suppress_ragged_eofs=True,
452 server_hostname=None, session=None):
453 # SSLSocket class handles server_hostname encoding before it calls
454 # ctx._wrap_socket()
--> 455 return self.sslsocket_class._create(
456 sock=sock,
457 server_side=server_side,
458 do_handshake_on_connect=do_handshake_on_connect,
459 suppress_ragged_eofs=suppress_ragged_eofs,
460 server_hostname=server_hostname,
461 context=self,
462 session=session
463 )
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:1041, in SSLSocket._create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)
1040 raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
-> 1041 self.do_handshake()
1042 except:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:1319, in SSLSocket.do_handshake(self, block)
1318 self.settimeout(None)
-> 1319 self._sslobj.do_handshake()
1320 finally:
ConnectionResetError: [Errno 104] Connection reset by peer
During handling of the above exception, another exception occurred:
ProtocolError Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/adapters.py:696, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
695 try:
--> 696 resp = conn.urlopen(
697 method=request.method,
698 url=url,
699 body=request.body, # type: ignore[arg-type] # urllib3 stubs don't accept Iterable[bytes | str]
700 headers=request.headers, # type: ignore[arg-type] # urllib3#3072
701 redirect=False,
702 assert_same_host=False,
703 preload_content=False,
704 decode_content=False,
705 retries=self.max_retries,
706 timeout=resolved_timeout,
707 chunked=chunked,
708 )
710 except (ProtocolError, OSError) as err:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:842, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
840 new_e = ProtocolError("Connection aborted.", new_e)
--> 842 retries = retries.increment(
843 method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
844 )
845 retries.sleep()
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/retry.py:498, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
497 if read is False or method is None or not self._is_method_retryable(method):
--> 498 raise reraise(type(error), error, _stacktrace)
499 elif read is not None:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/util.py:38, in reraise(tp, value, tb)
37 if value.__traceback__ is not tb:
---> 38 raise value.with_traceback(tb)
39 raise value
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:788, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
787 # Make the request on the HTTPConnection object
--> 788 response = self._make_request(
789 conn,
790 method,
791 url,
792 timeout=timeout_obj,
793 body=body,
794 headers=headers,
795 chunked=chunked,
796 retries=retries,
797 response_conn=response_conn,
798 preload_content=preload_content,
799 decode_content=decode_content,
800 **response_kw,
801 )
803 # Everything went great!
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:488, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
487 new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
--> 488 raise new_e
490 # conn.request() calls http.client.*.request, not the method in
491 # urllib3.request. It also calls makefile (recv) on the socket.
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:464, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
463 try:
--> 464 self._validate_conn(conn)
465 except (SocketTimeout, BaseSSLError) as e:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:1106, in HTTPSConnectionPool._validate_conn(self, conn)
1105 if conn.is_closed:
-> 1106 conn.connect()
1108 # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connection.py:796, in HTTPSConnection.connect(self)
794 server_hostname_rm_dot = server_hostname.rstrip(".")
--> 796 sock_and_verified = _ssl_wrap_socket_and_match_hostname(
797 sock=sock,
798 cert_reqs=self.cert_reqs,
799 ssl_version=self.ssl_version,
800 ssl_minimum_version=self.ssl_minimum_version,
801 ssl_maximum_version=self.ssl_maximum_version,
802 ca_certs=self.ca_certs,
803 ca_cert_dir=self.ca_cert_dir,
804 ca_cert_data=self.ca_cert_data,
805 cert_file=self.cert_file,
806 key_file=self.key_file,
807 key_password=self.key_password,
808 server_hostname=server_hostname_rm_dot,
809 ssl_context=self.ssl_context,
810 tls_in_tls=tls_in_tls,
811 assert_hostname=self.assert_hostname,
812 assert_fingerprint=self.assert_fingerprint,
813 )
814 self.sock = sock_and_verified.socket
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/connection.py:975, in _ssl_wrap_socket_and_match_hostname(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)
973 server_hostname = normalized
--> 975 ssl_sock = ssl_wrap_socket(
976 sock=sock,
977 keyfile=key_file,
978 certfile=cert_file,
979 key_password=key_password,
980 ca_certs=ca_certs,
981 ca_cert_dir=ca_cert_dir,
982 ca_cert_data=ca_cert_data,
983 server_hostname=server_hostname,
984 ssl_context=context,
985 tls_in_tls=tls_in_tls,
986 )
988 try:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/ssl_.py:433, in ssl_wrap_socket(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)
431 context.set_alpn_protocols(ALPN_PROTOCOLS)
--> 433 ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
434 return ssl_sock
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/urllib3/util/ssl_.py:477, in _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname)
475 return SSLTransport(sock, ssl_context, server_hostname)
--> 477 return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:455, in SSLContext.wrap_socket(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)
449 def wrap_socket(self, sock, server_side=False,
450 do_handshake_on_connect=True,
451 suppress_ragged_eofs=True,
452 server_hostname=None, session=None):
453 # SSLSocket class handles server_hostname encoding before it calls
454 # ctx._wrap_socket()
--> 455 return self.sslsocket_class._create(
456 sock=sock,
457 server_side=server_side,
458 do_handshake_on_connect=do_handshake_on_connect,
459 suppress_ragged_eofs=suppress_ragged_eofs,
460 server_hostname=server_hostname,
461 context=self,
462 session=session
463 )
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:1041, in SSLSocket._create(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)
1040 raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
-> 1041 self.do_handshake()
1042 except:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/ssl.py:1319, in SSLSocket.do_handshake(self, block)
1318 self.settimeout(None)
-> 1319 self._sslobj.do_handshake()
1320 finally:
ProtocolError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
During handling of the above exception, another exception occurred:
ConnectionError Traceback (most recent call last)
Cell In[4], line 7
3 # The COD database contains methods to filter phases in the chemical system
4 cod_database = CODDatabase()
5
6 # gather reference phases and save them to a directory called "cifs"
----> 7 all_icsd_ids = cod_database.get_cifs_by_chemsys(chemical_system, dest_dir="cifs")
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dara/structure_db.py:107, in StructureDatabase.get_cifs_by_chemsys(self, chemsys, e_hull_filter, copy_files, dest_dir, exclude_gases)
104 if sub_chemsys in self.preparsed_info:
105 all_data.extend(self.preparsed_info[sub_chemsys])
--> 107 file_map = self._generate_file_map(all_data, e_hull_filter, exclude_gases)
109 if copy_files:
110 copy_and_rename_files(file_map, dest_dir)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dara/structure_db.py:148, in StructureDatabase._generate_file_map(self, all_data, e_hull_filter, exclude_gases, download_folder)
144 if not self.local_copy_found:
145 logger.warning(
146 "Local copy of database not found. Attempting to download structures..."
147 )
--> 148 _ = self.download_structures(
149 [data[1] for data in all_data],
150 save=True,
151 default_folder=download_folder,
152 )
154 file_map = {}
155 for formula, code, sg, e_hull in all_data:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dara/structure_db.py:259, in CODDatabase.download_structures(self, ids, save, default_folder)
247 def download_structures(
248 self,
249 ids: list[str] | None = None,
250 save=False,
251 default_folder="downloaded_cod_cifs",
252 ) -> list[Cif]:
253 """Download structures from the COD database. Note that this downloads directly
254 from the COD website, so it may be slow. Please do not abuse this feature.
255
256 Args:
257 ids: List of COD IDs to download.
258 """
--> 259 cifs = thread_map(
260 self._download_cod,
261 ids,
262 chunksize=1,
263 max_workers=16,
264 desc="Downloading CIFs from COD...",
265 )
266 if save:
267 logger.info(f"Saving downloaded CIFs to {default_folder}")
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/tqdm/contrib/concurrent.py:191, in thread_map(fn, *iterables, **tqdm_kwargs)
168 """
169 Equivalent of `list(map(fn, *iterables))`
170 driven by `concurrent.futures.ThreadPoolExecutor`.
(...) 188 Member of `tqdm_class.get_lock()` to use [default: ''].
189 """
190 from concurrent.futures import ThreadPoolExecutor
--> 191 return _executor_map(ThreadPoolExecutor, fn, *iterables, **tqdm_kwargs)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/tqdm/contrib/concurrent.py:163, in _executor_map(PoolExecutor, fn, max_workers, timeout, chunksize, lock_name, tqdm_class, smoothing, _lock, _initializer, _initargs, *iterables, **tqdm_kwargs)
161 return fut
162 ex.submit = patchsubmit
--> 163 return list(ex.map(
164 fn, *iterables, timeout=timeout, chunksize=chunksize, **map_kwargs))
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/concurrent/futures/_base.py:619, in Executor.map.<locals>.result_iterator()
616 while fs:
617 # Careful not to keep a reference to the popped future
618 if timeout is None:
--> 619 yield _result_or_cancel(fs.pop())
620 else:
621 yield _result_or_cancel(fs.pop(), end_time - time.monotonic())
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/concurrent/futures/_base.py:317, in _result_or_cancel(***failed resolving arguments***)
315 try:
316 try:
--> 317 return fut.result(timeout)
318 finally:
319 fut.cancel()
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/concurrent/futures/_base.py:456, in Future.result(self, timeout)
454 raise CancelledError()
455 elif self._state == FINISHED:
--> 456 return self.__get_result()
457 else:
458 raise TimeoutError()
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/concurrent/futures/_base.py:401, in Future.__get_result(self)
399 if self._exception:
400 try:
--> 401 raise self._exception
402 finally:
403 # Break a reference cycle with the exception in self._exception
404 self = None
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/concurrent/futures/thread.py:59, in _WorkItem.run(self)
56 return
58 try:
---> 59 result = self.fn(*self.args, **self.kwargs)
60 except BaseException as exc:
61 self.future.set_exception(exc)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/dara/structure_db.py:302, in CODDatabase._download_cod(cod_id)
300 try:
301 url = COD_URL.format(cod_id=cod_id)
--> 302 response = requests.get(url, timeout=30)
303 response.raise_for_status() # Raise an error for bad status codes
304 with NamedTemporaryFile(mode="w+b") as temp_file:
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/api.py:87, in get(url, params, **kwargs)
74 def get(
75 url: _t.UriType, params: _t.ParamsType = None, **kwargs: Unpack[_t.GetKwargs]
76 ) -> Response:
77 r"""Sends a GET request.
78
79 :param url: URL for the new :class:`Request` object.
(...) 84 :rtype: requests.Response
85 """
---> 87 return request("get", url, params=params, **kwargs)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/api.py:71, in request(method, url, **kwargs)
67 # By using the 'with' statement we are sure the session is closed, thus we
68 # avoid leaving sockets open which can trigger a ResourceWarning in some
69 # cases, and look like a memory leak in others.
70 with sessions.Session() as session:
---> 71 return session.request(method=method, url=url, **kwargs)
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/sessions.py:651, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
646 send_kwargs = {
647 "timeout": timeout,
648 "allow_redirects": allow_redirects,
649 }
650 send_kwargs.update(settings)
--> 651 resp = self.send(prep, **send_kwargs)
653 return resp
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/sessions.py:784, in Session.send(self, request, **kwargs)
781 start = preferred_clock()
783 # Send the request
--> 784 r = adapter.send(request, **kwargs)
786 # Total elapsed time of the request (approximately)
787 elapsed = preferred_clock() - start
File /opt/hostedtoolcache/Python/3.12.13/x64/lib/python3.12/site-packages/requests/adapters.py:711, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
696 resp = conn.urlopen(
697 method=request.method,
698 url=url,
(...) 707 chunked=chunked,
708 )
710 except (ProtocolError, OSError) as err:
--> 711 raise ConnectionError(err, request=request)
713 except MaxRetryError as e:
714 if isinstance(e.reason, ConnectTimeoutError):
715 # TODO: Remove this in 3.0.0: see #2811
ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Since we are using a pre-filterd database (i.e., the COD), the downloaded CIF files will automatically be named according to the following convention:
{composition}_{spacegroup}_(cod|icsd_{id})-{e_hull}.cif
Where the e_hull is the energy above the convex hull in meV/atom, as determined from
the Materials Project database for the ground-state entry with matching composition and spacegroup.
Step 2: Search for phases#
After preparing the reference CIFs, we can start the phase search on a provided XRD pattern.
In this case, we are using the XRD pattern from the solid-state reaction sample
on our laboratory’s Aeris diffractometer (tutorial_data/GeO2-ZnO_700C_60min.xrdml).
# gather all the phases in the "cifs" directory
all_cifs = list(Path("cifs").glob("*.cif"))
search_results = search_phases(
pattern_path=pattern_path,
phases=all_cifs,
wavelength="Cu",
instrument_profile="Aeris-fds-Pixcel1d-Medipix3",
)
2024-06-26 14:30:14,946 INFO dara.search.tree Detecting peaks in the pattern.
2024-06-26 14:30:24,693 INFO dara.search.tree The wmax is automatically adjusted to 57.88.
2024-06-26 14:30:24,694 INFO dara.search.tree The intensity threshold is automatically set to 10.00 % of maximum peak intensity.
2024-06-26 14:30:24,695 INFO dara.search.tree Creating the root node.
2024-06-26 14:30:24,695 INFO dara.search.tree Refining all the phases in the dataset.
2024-06-26 14:30:26,609 INFO worker.py:1724 -- Started a local Ray instance.
2024-06-26 14:30:46,723 INFO dara.search.tree Finished refining 36 phases, with 14 phases removed.
(_remote_expand_node pid=58061) 2024-06-26 14:30:46,756 INFO dara.search.tree Expanding node 4ca12eb6-3403-11ef-bdbc-8adca62d6f4b with current phases [], Rwp = None
(_remote_expand_node pid=58061) 2024-06-26 14:30:47,937 INFO dara.search.tree Expanding node 5a5bde0c-3403-11ef-ab24-8adca62d6f4b with current phases [RefinementPhase(path=PosixPath('cifs/GeO2_152_(cod_2300365)-0.cif'), params={})], Rwp = 42.15
(_remote_expand_node pid=58052) 2024-06-26 14:30:49,892 INFO dara.search.tree Expanding node 5b83ef90-3403-11ef-9b6b-8adca62d6f4b with current phases [RefinementPhase(path=PosixPath('cifs/ZnO_186_(cod_9004178)-0.cif'), params={}), RefinementPhase(path=PosixPath('cifs/Zn2GeO4_148_(cod_9014631)-0.cif'), params={})], Rwp = 44.26
(_remote_expand_node pid=58054) 2024-06-26 14:30:51,613 INFO dara.search.tree Expanding node 5c7ff312-3403-11ef-b006-8adca62d6f4b with current phases [RefinementPhase(path=PosixPath('cifs/GeO2_152_(cod_2300365)-0.cif'), params={}), RefinementPhase(path=PosixPath('cifs/ZnO_186_(cod_9004178)-0.cif'), params={}), RefinementPhase(path=PosixPath('cifs/Zn2GeO4_148_(cod_9014631)-0.cif'), params={})], Rwp = 12.04
Step 3: Result analysis#
The returned search result will be a list of SearchResult object.
search_results
[SearchResult(refinement_result=RefinementResult(lst_data=LstResult(raw_lst='Rietveld refinement to file(s) GeO2-ZnO_700C_60min.xy\nBGMN version 4.2.23, 4416 measured points, 121 peaks, 24 parameters\nStart: Wed Jun 26 14:30:50 2024; End: Wed Jun 26 14:30:51 2024\n20 iteration steps\n\nRp=9.96% Rpb=19.06% R=10.99% Rwp=12.04% Rexp=2.69%\nDurbin-Watson d=0.10\n1-rho=1.99%\n\nGlobal parameters and GOALs\n****************************\nQGeO2152cod23003650=0.4771+-0.0021\nQZnO186cod90041780=0.3870+-0.0024\nQZn2GeO4148cod90146310=0.1359+-0.0013\nEPS2=-0.002856+-0.000013\n\nLocal parameters and GOALs for phase GeO2152cod23003650\n******************************************************\nSpacegroupNo=152\nHermannMauguin=P3_121\nXrayDensity=4.276\nRphase=10.88%\nUNIT=NM\nA=0.499111+-0.000024\nC=0.564768+-0.000033\nk1=0.0100000\nB1=0.00500000\nGEWICHT=0.2793+-0.0012\nGrainSize(1,1,1)=84.1811\nAtomic positions for phase GeO2152cod23003650\n---------------------------------------------\n 3 0.4512 0.0000 0.3333 E=(GE(1.0000))\n 6 0.3974 0.3022 0.2429 E=(O(1.0000))\n\nLocal parameters and GOALs for phase ZnO186cod90041780\n******************************************************\nSpacegroupNo=186\nHermannMauguin=P6_3mc\nXrayDensity=5.669\nRphase=9.52%\nUNIT=NM\nA=0.325072+-0.000011\nC=0.520812+-0.000030\nk1=0\nB1=0.003509+-0.000094\nGEWICHT=0.2266+-0.0021\nGrainSize(1,1,1)=120.9+-3.2\nAtomic positions for phase ZnO186cod90041780\n---------------------------------------------\n 2 0.3333 0.6667 0.0000 E=(ZN(1.0000))\n 2 0.3333 0.6667 0.3821 E=(O(1.0000))\n\nLocal parameters and GOALs for phase Zn2GeO4148cod90146310\n******************************************************\nSpacegroupNo=148\nHermannMauguin=R-3\nXrayDensity=4.777\nRphase=20.28%\nUNIT=NM\nA=1.423755+-0.000083\nC=0.952849+-0.000079\nk1=0.0100000\nB1=0.00500000\nGEWICHT=0.07959+-0.00075\nGrainSize(1,1,1)=84.1811\nAtomic positions for phase Zn2GeO4148cod90146310\n---------------------------------------------\n 18 0.2150 0.1940 0.5830 E=(ZN(1.0000))\n 18 0.5483 0.8607 0.5837 E=(ZN(1.0000))\n 18 0.2150 0.1940 0.2500 E=(GE(1.0000))\n 18 0.8877 0.4633 0.4293 E=(O(1.0000))\n 18 0.2220 0.1310 0.4030 E=(O(1.0000))\n 18 0.2230 0.1140 0.7500 E=(O(1.0000))\n 18 0.9957 0.6613 0.5833 E=(O(1.0000))\n', pattern_name='GeO2-ZnO_700C_60min.xy', num_steps=20, rp=9.96, rpb=19.06, r=10.99, rwp=12.04, rexp=2.69, d=0.1, rho=1.99, phases_results={'GeO2_152_(cod_2300365)-0': PhaseResult(spacegroup_no=152, hermann_mauguin='P3_121', xray_density=4.276, rphase=10.88, unit='NM', gewicht=(0.2793, 0.0012), gewicht_name=None, a=(0.499111, 2.4e-05), b=None, c=(0.564768, 3.3e-05), alpha=None, beta=None, gamma=None, k1=0.01, B1=0.005), 'ZnO_186_(cod_9004178)-0': PhaseResult(spacegroup_no=186, hermann_mauguin='P6_3mc', xray_density=5.669, rphase=9.52, unit='NM', gewicht=(0.2266, 0.0021), gewicht_name=None, a=(0.325072, 1.1e-05), b=None, c=(0.520812, 3e-05), alpha=None, beta=None, gamma=None, k1=0, B1=(0.003509, 9.4e-05)), 'Zn2GeO4_148_(cod_9014631)-0': PhaseResult(spacegroup_no=148, hermann_mauguin='R-3', xray_density=4.777, rphase=20.28, unit='NM', gewicht=(0.07959, 0.00075), gewicht_name=None, a=(1.423755, 8.3e-05), b=None, c=(0.952849, 7.9e-05), alpha=None, beta=None, gamma=None, k1=0.01, B1=0.005)})), phases=((RefinementPhase(path=PosixPath('cifs/GeO2_152_(cod_2300365)-0.cif'), params={}), RefinementPhase(path=PosixPath('cifs/GeO2_154_(cod_9007477)-0.cif'), params={})), (RefinementPhase(path=PosixPath('cifs/ZnO_186_(cod_9004178)-0.cif'), params={}),), (RefinementPhase(path=PosixPath('cifs/Zn2GeO4_148_(cod_9014631)-0.cif'), params={}),)), foms=((0.0,), (0.03536489998694256, 0.035273051226012), (0.13639804324187943,), (0.33427282595205166,)), lattice_strains=((0.0,), (0.000172525492243293, 0.0005005169609892967), (0.0005712782487738224,), (-0.0033382277696805732,)), missing_peaks=[], extra_peaks=[])]
In this pattern, we only have one solution found with Rwp = 12.04 %.
for i in range(len(search_results)):
print(f"Rwp of solution {i} = {search_results[i].refinement_result.lst_data.rwp} %")
Rwp of solution 0 = 12.04 %
Each SearchResult has a .visualize() method to visualize the refined pattern and
missing/extra peaks in the solution. If there are no missing or extra peaks, this option
will not appear.
search_results[0].visualize()
You can also view all the alternative phases in one solution from SearchResult.phases attribute.
print("Phases found in solution 0:")
for i, phases_ in enumerate(search_results[0].phases):
print(f" - Phase {i}: {[phase.path.name for phase in phases_]}")
Phases found in solution 0:
- Phase 0: ['GeO2_152_(cod_2300365)-0.cif', 'GeO2_154_(cod_9007477)-0.cif']
- Phase 1: ['ZnO_186_(cod_9004178)-0.cif']
- Phase 2: ['Zn2GeO4_148_(cod_9014631)-0.cif']
From the result, you can see that for the phase GeO2, the algorithm identifies two
similar phases with slightly different spacegroups (152 and 154).