From d7d720141e129bfe849b7fbe77695262042d9386 Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Wed, 5 Apr 2017 20:58:01 +0200 Subject: [PATCH 01/44] Port to new Python interface for Gf - Minor changes - tests are ok --- CMakeLists.txt | 4 ++-- python/block_structure.py | 2 +- python/converters/plovasp/examples/ce/hf_solver.py | 2 +- python/converters/plovasp/examples/srvo3/conv_example.py | 2 +- python/sumk_dft.py | 6 +++--- python/sumk_dft_tools.py | 6 +++--- python/symmetry.py | 2 +- python/trans_basis.py | 2 +- test/blockstructure.py | 2 +- test/sigma_from_file.py | 4 ++-- test/srvo3_Gloc.py | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f883b30e..15f67e33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # Version number of the application -set (DFT_TOOLS_VERSION "1.4") -set (DFT_TOOLS_RELEASE "1.4.0") +set (DFT_TOOLS_VERSION "1.5") +set (DFT_TOOLS_RELEASE "1.5.0") # Append triqs installed files to the cmake load path list(APPEND CMAKE_MODULE_PATH ${TRIQS_PATH}/share/triqs/cmake) diff --git a/python/block_structure.py b/python/block_structure.py index 9ae7f740..b0903161 100644 --- a/python/block_structure.py +++ b/python/block_structure.py @@ -1,6 +1,6 @@ import copy import numpy as np -from pytriqs.gf.local import GfImFreq, BlockGf +from pytriqs.gf import GfImFreq, BlockGf from ast import literal_eval from warnings import warn diff --git a/python/converters/plovasp/examples/ce/hf_solver.py b/python/converters/plovasp/examples/ce/hf_solver.py index 41a96c02..64005660 100644 --- a/python/converters/plovasp/examples/ce/hf_solver.py +++ b/python/converters/plovasp/examples/ce/hf_solver.py @@ -23,7 +23,7 @@ from types import * #from pytriqs.applications.dft.U_matrix import * from U_matrix import * -from pytriqs.gf.local import * +from pytriqs.gf import * #from hubbard_I import gf_hi_fullu, sigma_atomic_fullu import pytriqs.utility.mpi as mpi from itertools import izip diff --git a/python/converters/plovasp/examples/srvo3/conv_example.py b/python/converters/plovasp/examples/srvo3/conv_example.py index 011ff3ba..21850573 100644 --- a/python/converters/plovasp/examples/srvo3/conv_example.py +++ b/python/converters/plovasp/examples/srvo3/conv_example.py @@ -1,6 +1,6 @@ import numpy as np -from pytriqs.gf.local import * +from pytriqs.gf import * #from sumk_dft import SumkDFT from sumk_dft_tools import SumkDFTTools from converters.vasp_converter import VaspConverter diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 7a7db48a..2d32d4a2 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -23,7 +23,7 @@ from types import * import numpy import pytriqs.utility.dichotomy as dichotomy -from pytriqs.gf.local import * +from pytriqs.gf import * import pytriqs.utility.mpi as mpi from pytriqs.archive import * from symmetry import * @@ -593,13 +593,13 @@ class SumkDFT(object): Sigma_imp) == self.n_inequiv_shells, "put_Sigma: give exactly one Sigma for each inequivalent corr. shell!" # init self.Sigma_imp_(i)w: - if all(type(gf) == GfImFreq for bname, gf in Sigma_imp[0]): + if all( (isinstance(gf, Gf) and isinstance (gf.mesh, MeshImFreq)) for bname, gf in Sigma_imp[0]): # Imaginary frequency Sigma: self.Sigma_imp_iw = [BlockGf(name_block_generator=[(block, GfImFreq(indices=inner, mesh=Sigma_imp[0].mesh)) for block, inner in self.gf_struct_sumk[icrsh]], make_copies=False) for icrsh in range(self.n_corr_shells)] SK_Sigma_imp = self.Sigma_imp_iw - elif all(type(gf) == GfReFreq for bname, gf in Sigma_imp[0]): + elif all( isinstance(gf, Gf) and isinstance (gf.mesh, MeshReFreq) for bname, gf in Sigma_imp[0]): # Real frequency Sigma: self.Sigma_imp_w = [BlockGf(name_block_generator=[(block, GfReFreq(indices=inner, mesh=Sigma_imp[0].mesh)) for block, inner in self.gf_struct_sumk[icrsh]], make_copies=False) diff --git a/python/sumk_dft_tools.py b/python/sumk_dft_tools.py index 8d0dd2de..46ead06c 100644 --- a/python/sumk_dft_tools.py +++ b/python/sumk_dft_tools.py @@ -21,7 +21,7 @@ import sys from types import * import numpy -from pytriqs.gf.local import * +from pytriqs.gf import * import pytriqs.utility.mpi as mpi from symmetry import * from sumk_dft import SumkDFT @@ -767,8 +767,8 @@ class SumkDFTTools(SumkDFT): self.Sigma_imp_w[icrsh] = BlockGf( name_list=spn, block_list=glist(), make_copies=False) for i, g in self.Sigma_imp_w[icrsh]: - for iL in g.indices: - for iR in g.indices: + for iL in g.indices[0]: + for iR in g.indices[0]: for iom in xrange(n_om): g.data[iom, int(iL), int(iR)] = Sigma_save[ i].data[ioffset + iom, int(iL), int(iR)] diff --git a/python/symmetry.py b/python/symmetry.py index 4b27b205..461587e8 100644 --- a/python/symmetry.py +++ b/python/symmetry.py @@ -23,7 +23,7 @@ import copy import numpy from types import * -from pytriqs.gf.local import * +from pytriqs.gf import * from pytriqs.archive import * import pytriqs.utility.mpi as mpi diff --git a/python/trans_basis.py b/python/trans_basis.py index d21ab66d..135e72c9 100644 --- a/python/trans_basis.py +++ b/python/trans_basis.py @@ -1,6 +1,6 @@ from pytriqs.applications.dft.sumk_dft import * from pytriqs.applications.dft.converters import Wien2kConverter -from pytriqs.gf.local import * +from pytriqs.gf import * from pytriqs.archive import * import pytriqs.utility.mpi as mpi import numpy diff --git a/test/blockstructure.py b/test/blockstructure.py index 0ba7989d..0d83123d 100644 --- a/test/blockstructure.py +++ b/test/blockstructure.py @@ -1,6 +1,6 @@ from pytriqs.applications.dft.sumk_dft import * from pytriqs.utility.h5diff import h5diff -from pytriqs.gf.local import * +from pytriqs.gf import * from pytriqs.utility.comparison_tests import assert_block_gfs_are_close from pytriqs.applications.dft import BlockStructure diff --git a/test/sigma_from_file.py b/test/sigma_from_file.py index 3e314253..7f8640c0 100644 --- a/test/sigma_from_file.py +++ b/test/sigma_from_file.py @@ -20,8 +20,8 @@ ################################################################################ from pytriqs.archive import * -from pytriqs.gf.local import * -from pytriqs.gf.local.tools import * +from pytriqs.gf import * +from pytriqs.gf.tools import * from pytriqs.applications.dft.sumk_dft_tools import * from pytriqs.utility.comparison_tests import * import numpy as np diff --git a/test/srvo3_Gloc.py b/test/srvo3_Gloc.py index d433b800..20f9d120 100644 --- a/test/srvo3_Gloc.py +++ b/test/srvo3_Gloc.py @@ -20,7 +20,7 @@ ################################################################################ from pytriqs.archive import * -from pytriqs.gf.local import * +from pytriqs.gf import * from pytriqs.applications.dft.sumk_dft import * from pytriqs.applications.dft.converters.wien2k_converter import * from pytriqs.operators.util import set_operator_structure From 56480d50c55443398892bac3cfe22899fa09e4f7 Mon Sep 17 00:00:00 2001 From: "Hugo U. R. Strand" Date: Wed, 4 Oct 2017 17:50:20 -0400 Subject: [PATCH 02/44] [sumk] gf.N1 deprecation warning fix --- python/sumk_dft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 2d32d4a2..024b7729 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -521,7 +521,7 @@ class SumkDFT(object): set_up_G_latt = True else: # Check that existing GF is consistent G_latt = getattr(self, "G_latt_" + iw_or_w) - GFsize = [gf.N1 for bname, gf in G_latt] + GFsize = [gf.target_shape[0] for bname, gf in G_latt] unchangedsize = all([self.n_orbitals[ik, ntoi[spn[isp]]] == GFsize[ isp] for isp in range(self.n_spin_blocks[self.SO])]) if not unchangedsize: From e5cd5c5aba791138b7d37bf9b67167152ed4ebf3 Mon Sep 17 00:00:00 2001 From: Manuel Zingl Date: Mon, 16 Oct 2017 10:15:20 +0200 Subject: [PATCH 03/44] Fix bug in writing qdmft file --- python/sumk_dft.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 2d32d4a2..e10704da 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1478,6 +1478,7 @@ class SumkDFT(object): for imu in range(self.n_orbitals[ik, isp]): fout.write("%.14f %.14f " % (deltaN[sp][ik][ inu, imu].real, deltaN[sp][ik][inu, imu].imag)) + fout.write("\n") fout.write("\n") fout.close() elif dm_type == 'vasp': From 78b8b1d0ee7d7731a96240e9153c3490802a49dc Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Tue, 24 Oct 2017 09:49:54 +0200 Subject: [PATCH 04/44] Fix default value of filename in calc_density_correction --- python/sumk_dft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 6554c7f9..900faff5 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1362,15 +1362,15 @@ class SumkDFT(object): """ assert dm_type in ('vasp', 'wien2k'), "'dm_type' must be either 'vasp' or 'wienk'" - assert type(filename) == StringType, ("calc_density_correction: " - "filename has to be a string!") - if filename is None: if dm_type == 'wien2k': filename = 'dens_mat.dat' elif dm_type == 'vasp': filename = 'GAMMA' - + + assert type(filename) == StringType, ("calc_density_correction: " + "filename has to be a string!") + ntoi = self.spin_names_to_ind[self.SO] spn = self.spin_block_names[self.SO] dens = {sp: 0.0 for sp in spn} From ae548d48da4a160c6cd82c54ec1353870657257a Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Thu, 7 Dec 2017 15:56:05 +0100 Subject: [PATCH 05/44] WIP --- CMakeLists.txt | 42 +++++++++++++----------- c++/plovasp/atm/CMakeLists.txt | 5 ++- c++/plovasp/atm/test/CMakeLists.txt | 19 +++-------- fortran/dmftproj/CMakeLists.txt | 2 +- python/CMakeLists.txt | 12 ++++--- python/converters/plovasp/CMakeLists.txt | 14 ++++---- python/converters/plovasp/atm_desc.py | 2 +- test/CMakeLists.txt | 21 ++++++------ 8 files changed, 56 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15f67e33..7b3383b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,45 +2,49 @@ set (DFT_TOOLS_VERSION "1.5") set (DFT_TOOLS_RELEASE "1.5.0") -# Append triqs installed files to the cmake load path -list(APPEND CMAKE_MODULE_PATH ${TRIQS_PATH}/share/triqs/cmake) +# Default to Release build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Type of build" FORCE) +endif() +message( STATUS "-------- BUILD-TYPE: ${CMAKE_BUILD_TYPE} -------------") -# start configuration +# start configuration cmake_minimum_required(VERSION 2.8) project(dft_tools CXX Fortran) -set(CMAKE_BUILD_TYPE Release) -enable_testing() -# Load TRIQS, including all predefined variables from TRIQS installation -find_package(TRIQS REQUIRED) +# Use shared libraries +set(BUILD_SHARED_LIBS ON) + +# Load TRIQS and Cpp2Py +find_package(TRIQS 1.5 EXACT REQUIRED) +find_package(Cpp2Py REQUIRED) -# Check that versions are compatible -if(NOT DFT_TOOLS_VERSION EQUAL TRIQS_VERSION) - message(FATAL_ERROR "The application version is not compatible with the TRIQS library (TRIQS library version: ${TRIQS_VERSION} while this application version: ${DFT_TOOLS_VERSION})") -endif() if (NOT ${TRIQS_WITH_PYTHON_SUPPORT}) MESSAGE(FATAL_ERROR "dft_tools require Python support in TRIQS") endif() -# Get hash -triqs_get_git_hash(${CMAKE_SOURCE_DIR} "DFT_TOOLS") -if(${GIT_RESULT} EQUAL 0) - message(STATUS "Hash: ${DFT_TOOLS_GIT_HASH}") -endif(${GIT_RESULT} EQUAL 0) +# Default Install directory to TRIQS_ROOT if not given. Checks an absolute name is given. +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR (NOT IS_ABSOLUTE ${CMAKE_INSTALL_PREFIX})) + message(STATUS " No install prefix given (or invalid). Defaulting to TRIQS_ROOT") + set(CMAKE_INSTALL_PREFIX ${TRIQS_ROOT} CACHE PATH "default install path" FORCE) +endif() +message(STATUS "-------- CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX} -------------") -# We want to be installed in the TRIQS tree -set(CMAKE_INSTALL_PREFIX ${TRIQS_PATH}) +# Macro defined in TRIQS which picks the hash of repo. +triqs_get_git_hash_of_source_dir(DFT_TOOLS_GIT_HASH) +message(STATUS "Git hash: ${DFT_TOOLS_GIT_HASH}") add_subdirectory(fortran/dmftproj) # Add the compiling options (-D... ) for C++ message(STATUS "TRIQS : Adding compilation flags detected by the library (C++11/14, libc++, etc...) ") -add_definitions(${TRIQS_CXX_DEFINITIONS}) add_subdirectory(c++) add_subdirectory(python) add_subdirectory(shells) add_subdirectory(test) + + option(BUILD_DOC "Build documentation" OFF) if(${BUILD_DOC}) if(NOT TRIQS_WITH_DOCUMENTATION) diff --git a/c++/plovasp/atm/CMakeLists.txt b/c++/plovasp/atm/CMakeLists.txt index 228e950f..eb8b8340 100644 --- a/c++/plovasp/atm/CMakeLists.txt +++ b/c++/plovasp/atm/CMakeLists.txt @@ -1,7 +1,6 @@ -# Linking and include info add_library(atm_c dos_tetra3d.hpp dos_tetra3d.cpp argsort.hpp argsort.cpp) -set_target_properties(atm_c PROPERTIES LINKER_LANGUAGE CXX) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/c++/plovasp/atm ${TRIQS_INCLUDE_ALL}) +target_link_libraries(atm_c triqs) +target_compile_options(atm_c PRIVATE -std=c++14) install(TARGETS atm_c DESTINATION lib) diff --git a/c++/plovasp/atm/test/CMakeLists.txt b/c++/plovasp/atm/test/CMakeLists.txt index eaecd9ed..d592f23c 100644 --- a/c++/plovasp/atm/test/CMakeLists.txt +++ b/c++/plovasp/atm/test/CMakeLists.txt @@ -1,24 +1,13 @@ -find_package(TriqsTest) enable_testing() -# Linking and include info -#add_library(atm_c dos_tetra3d.hpp dos_tetra3d.cpp argsort.h argsort.c) -#set_target_properties(atm_c PROPERTIES LINKER_LANGUAGE CXX) -#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/c++/plovasp/atm ${TRIQS_INCLUDE_ALL}) - FILE(GLOB TestList RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) FOREACH( TestName1 ${TestList} ) STRING(REPLACE ".cpp" "" TestName ${TestName1}) - add_executable( ${TestName} ${CMAKE_CURRENT_SOURCE_DIR}/${TestName}.cpp ) - target_link_libraries( ${TestName} atm_c ${TRIQS_LIBRARY_ALL} ) + add_executable( ${TestName} ${TestName}.cpp ) + target_link_libraries( ${TestName} atm_c triqs) triqs_set_rpath_for_target( ${TestName} ) - triqs_add_cpp_test( ${TestName} ) - if (TESTS_C_WITH_VALGRIND) - add_test ( ${TestName}_valgrind valgrind --error-exitcode=1 ${CMAKE_CURRENT_BINARY_DIR}/${TestName}) - endif() + add_test(NAME ${TestName} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${t}) ENDFOREACH( TestName1 ${TestList} ) -#add_executable(test_atm test2py.cpp) -#target_link_libraries(test_atm atm_c) -#add_subdirectory(test) + diff --git a/fortran/dmftproj/CMakeLists.txt b/fortran/dmftproj/CMakeLists.txt index 2db677c8..7e66708b 100644 --- a/fortran/dmftproj/CMakeLists.txt +++ b/fortran/dmftproj/CMakeLists.txt @@ -6,7 +6,7 @@ set(SOURCES modules.f dmftproj.f readcomline.f set_ang_trans.f setsym.f # The main target and what to link with... add_executable(dmftproj ${SOURCES}) -target_link_libraries(dmftproj ${TRIQS_LIBRARY_LAPACK}) +target_link_libraries(dmftproj "-framework Accelerate") #${TRIQS_LIBRARY_LAPACK}) # where to install install (TARGETS dmftproj DESTINATION bin) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 426c3a74..32a92ef2 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,16 +1,18 @@ # where will the python end up in triqs? set(python_destination pytriqs/applications/dft) +set(PYTHON_LIB_DEST ${CPP2PY_PYTHON_LIB_DEST_ROOT}/pytriqs/cthyb) # site_customize for build set(package_name "pytriqs.applications") configure_file(${CMAKE_SOURCE_DIR}/cmake/sitecustomize.py ${CMAKE_CURRENT_BINARY_DIR}/sitecustomize.py @ONLY) -# make a local pytriqs copy -triqs_prepare_local_pytriqs(${python_destination}) - # VASP converter add_subdirectory(converters/plovasp) # add version file -configure_file(version.py.in version.py) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.py DESTINATION ${TRIQS_PYTHON_LIB_DEST_ROOT}/${python_destination}) +configure_file(version.py.in version.py @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.py DESTINATION ${PYTHON_LIB_DEST}) + + + + diff --git a/python/converters/plovasp/CMakeLists.txt b/python/converters/plovasp/CMakeLists.txt index 6271b4b0..67c7b732 100644 --- a/python/converters/plovasp/CMakeLists.txt +++ b/python/converters/plovasp/CMakeLists.txt @@ -1,11 +1,13 @@ set(python_destination pytriqs/applications/dft/converters/plovasp) -include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${TRIQS_INCLUDE_ALL}) -triqs_python_extension(atm ${python_destination}) -target_link_libraries(atm atm_c ${TRIQS_LIBRARY_ALL}) -triqs_set_rpath_for_target(atm) +add_cpp2py_module(atm) +target_link_libraries(atm atm_c triqs) +#triqs_set_rpath_for_target(atm) +target_compile_options(atm PRIVATE -std=c++14) # This we need in order for tests to work -add_custom_command(TARGET atm POST_BUILD COMMAND ln -fs ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}/atm.so ${CMAKE_BINARY_DIR}/python/dft/converters/plovasp) +#add_custom_command(TARGET atm POST_BUILD COMMAND ln -fs ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}/atm.so ${CMAKE_BINARY_DIR}/python/dft/converters/plovasp) + +install (TARGETS atm DESTINATION ${PYTHON_LIB_DEST}) + -install (TARGETS atm DESTINATION ${TRIQS_PYTHON_LIB_DEST_ROOT}/${python_destination}) diff --git a/python/converters/plovasp/atm_desc.py b/python/converters/plovasp/atm_desc.py index 48795a03..1fd53f01 100644 --- a/python/converters/plovasp/atm_desc.py +++ b/python/converters/plovasp/atm_desc.py @@ -1,6 +1,6 @@ # Generated automatically using the command : # c++2py.py -m atm -o atm --moduledoc "Analytical Tetrahedron Method for DOS" ../../../c++/plovasp/atm/dos_tetra3d.hpp -from wrap_generator import * +from cpp2py.wrap_generator import * # The module module = module_(full_name = "atm", doc = "Analytical Tetrahedron Method for calculating DOS", app_name = "atm") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e4edc52a..5ebe0867 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,20 +1,19 @@ -# load triqs helper to set up tests -find_package(TriqsTest) - # Copy h5 files to binary dir FILE(GLOB all_h5_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h5) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${all_h5_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # Copy other files FILE(COPY SrVO3.pmat SrVO3.struct SrVO3.outputs SrVO3.oubwin SrVO3.ctqmcout SrVO3.symqmc SrVO3.sympar SrVO3.parproj hk_convert_hamiltonian.hk LaVO3-Pnma_hr.dat LaVO3-Pnma.inp DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -triqs_add_python_test(wien2k_convert) -triqs_add_python_test(hk_convert) -triqs_add_python_test(w90_convert) -triqs_add_python_test(sumkdft_basic) -triqs_add_python_test(srvo3_Gloc) -triqs_add_python_test(srvo3_transp) -triqs_add_python_test(sigma_from_file) -triqs_add_python_test(blockstructure) +# List all tests +set(all_tests wien2k_convert hk_convert w90_convert sumkdft_basic srvo3_Gloc srvo3_transp sigma_from_file blockstructure) + +foreach(t ${all_tests}) + add_test(NAME ${t} COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/${t}.py) +endforeach() + +# Set the PythonPath : put the build dir first (in case there is an installed version). +set_property(TEST ${all_tests} PROPERTY ENVIRONMENT PYTHONPATH=${CMAKE_BINARY_DIR}/python:$ENV{PYTHONPATH} ) + # VASP converter tests add_subdirectory(plovasp) From 76dff0f5a2b79860e5c20d4aeb557c0b318de6f3 Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 22 Jan 2018 17:36:21 -0500 Subject: [PATCH 06/44] find lapack --- fortran/dmftproj/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fortran/dmftproj/CMakeLists.txt b/fortran/dmftproj/CMakeLists.txt index 7e66708b..4c202375 100644 --- a/fortran/dmftproj/CMakeLists.txt +++ b/fortran/dmftproj/CMakeLists.txt @@ -6,7 +6,8 @@ set(SOURCES modules.f dmftproj.f readcomline.f set_ang_trans.f setsym.f # The main target and what to link with... add_executable(dmftproj ${SOURCES}) -target_link_libraries(dmftproj "-framework Accelerate") #${TRIQS_LIBRARY_LAPACK}) +find_package(LAPACK) +target_link_libraries(dmftproj ${LAPACK_LIBRARIES}) # where to install install (TARGETS dmftproj DESTINATION bin) From 1a0ba43f8d470a00c676de81b67f670991453ba8 Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Mon, 22 Jan 2018 17:34:20 -0500 Subject: [PATCH 07/44] Continued --- CMakeLists.txt | 15 ++++++++++++++- c++/plovasp/atm/CMakeLists.txt | 2 +- python/CMakeLists.txt | 9 ++++++++- python/converters/converter_tools.py | 4 +--- python/converters/plovasp/CMakeLists.txt | 3 ++- python/converters/plovasp/atm_desc.py | 4 ++-- test/blockstructure.py | 4 ++-- test/hk_convert.py | 3 ++- test/plovasp/atm/test_atm.py | 2 +- test/plovasp/inpconf/test_general.py | 2 +- test/plovasp/inpconf/test_groups.py | 2 +- test/plovasp/inpconf/test_input.py | 2 +- test/plovasp/inpconf/test_parameter_set.py | 2 +- test/plovasp/inpconf/test_shells.py | 2 +- test/plovasp/inpconf/test_special_parsers.py | 2 +- test/plovasp/plotools/test_consistency.py | 8 ++++---- test/plovasp/proj_group/test_block_map.py | 6 +++--- test/plovasp/proj_group/test_one_site.py | 10 +++++----- test/plovasp/proj_group/test_select_bands.py | 10 +++++----- test/plovasp/proj_group/test_two_site.py | 10 +++++----- test/plovasp/proj_shell/test_projshells.py | 10 +++++----- test/plovasp/vaspio/test_doscar.py | 2 +- test/plovasp/vaspio/test_eigenval.py | 2 +- test/plovasp/vaspio/test_kpoints.py | 2 +- test/plovasp/vaspio/test_poscar.py | 2 +- test/sigma_from_file.py | 2 +- test/srvo3_Gloc.py | 4 ++-- test/srvo3_transp.py | 6 +++--- test/sumkdft_basic.py | 2 +- test/w90_convert.py | 2 +- test/wien2k_convert.py | 3 ++- 31 files changed, 80 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b3383b1..97c6d461 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,9 +42,22 @@ message(STATUS "TRIQS : Adding compilation flags detected by the library (C++11/ add_subdirectory(c++) add_subdirectory(python) add_subdirectory(shells) -add_subdirectory(test) +#------------------------ +# tests +#------------------------ + +enable_testing() + +option(Build_Tests "Build the tests of the library " ON) +if (Build_Tests) + message(STATUS "-------- Preparing tests -------------") + add_subdirectory(test) +endif() +#------------------------ +# Documentation +#------------------------ option(BUILD_DOC "Build documentation" OFF) if(${BUILD_DOC}) if(NOT TRIQS_WITH_DOCUMENTATION) diff --git a/c++/plovasp/atm/CMakeLists.txt b/c++/plovasp/atm/CMakeLists.txt index eb8b8340..afcb0176 100644 --- a/c++/plovasp/atm/CMakeLists.txt +++ b/c++/plovasp/atm/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(atm_c dos_tetra3d.hpp dos_tetra3d.cpp argsort.hpp argsort.cpp) target_link_libraries(atm_c triqs) -target_compile_options(atm_c PRIVATE -std=c++14) +target_compile_options(atm_c PRIVATE -std=c++17) install(TARGETS atm_c DESTINATION lib) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 32a92ef2..3e481102 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -4,7 +4,14 @@ set(PYTHON_LIB_DEST ${CPP2PY_PYTHON_LIB_DEST_ROOT}/pytriqs/cthyb) # site_customize for build set(package_name "pytriqs.applications") -configure_file(${CMAKE_SOURCE_DIR}/cmake/sitecustomize.py ${CMAKE_CURRENT_BINARY_DIR}/sitecustomize.py @ONLY) + +# Create a temporary copy of the python modules so that we can run before installation with the test +FILE(GLOB_RECURSE all_py_files RELATIVE ${CMAKE_SOURCE_DIR}/python *.py ) +foreach(f ${all_py_files}) + configure_file(${f} ${f} COPYONLY) +endforeach() + +#configure_file(${CMAKE_SOURCE_DIR}/cmake/sitecustomize.py ${CMAKE_CURRENT_BINARY_DIR}/sitecustomize.py @ONLY) # VASP converter add_subdirectory(converters/plovasp) diff --git a/python/converters/converter_tools.py b/python/converters/converter_tools.py index 126ffd57..b971518d 100644 --- a/python/converters/converter_tools.py +++ b/python/converters/converter_tools.py @@ -19,10 +19,8 @@ # TRIQS. If not, see . # ########################################################################## -from pytriqs.cmake_info import hdf5_command_path import pytriqs.utility.mpi as mpi - class ConverterTools: def __init__(self): @@ -73,7 +71,7 @@ class ConverterTools: mpi.report("Repacking the file %s" % self.hdf_file) retcode = subprocess.call( - [hdf5_command_path + "/h5repack", "-i%s" % self.hdf_file, "-otemphgfrt.h5"]) + ["h5repack", "-i%s" % self.hdf_file, "-otemphgfrt.h5"]) if retcode != 0: mpi.report("h5repack failed!") else: diff --git a/python/converters/plovasp/CMakeLists.txt b/python/converters/plovasp/CMakeLists.txt index 67c7b732..f9750662 100644 --- a/python/converters/plovasp/CMakeLists.txt +++ b/python/converters/plovasp/CMakeLists.txt @@ -3,7 +3,8 @@ set(python_destination pytriqs/applications/dft/converters/plovasp) add_cpp2py_module(atm) target_link_libraries(atm atm_c triqs) #triqs_set_rpath_for_target(atm) -target_compile_options(atm PRIVATE -std=c++14) +target_compile_options(atm PRIVATE -std=c++17) +target_include_directories(atm PRIVATE ${CMAKE_SOURCE_DIR}/c++) # This we need in order for tests to work #add_custom_command(TARGET atm POST_BUILD COMMAND ln -fs ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}/atm.so ${CMAKE_BINARY_DIR}/python/dft/converters/plovasp) diff --git a/python/converters/plovasp/atm_desc.py b/python/converters/plovasp/atm_desc.py index 1fd53f01..ac3776f0 100644 --- a/python/converters/plovasp/atm_desc.py +++ b/python/converters/plovasp/atm_desc.py @@ -8,11 +8,11 @@ module = module_(full_name = "atm", doc = "Analytical Tetrahedron Method for cal # All the triqs C++/Python modules # Add here all includes beyond what is automatically included by the triqs modules -module.add_include("../../../c++/plovasp/atm/dos_tetra3d.hpp") +module.add_include("plovasp/atm/dos_tetra3d.hpp") # Add here anything to add in the C++ code at the start, e.g. namespace using module.add_preamble(""" -#include +#include """) module.add_function ("array_view dos_tetra_weights_3d (array_view eigk, double en, array_view itt)", doc = """DOS of a band by analytical tetrahedron method\n\n Returns corner weights for all tetrahedra for a given band and real energy.""") diff --git a/test/blockstructure.py b/test/blockstructure.py index 0d83123d..33f1a570 100644 --- a/test/blockstructure.py +++ b/test/blockstructure.py @@ -1,8 +1,8 @@ -from pytriqs.applications.dft.sumk_dft import * +from sumk_dft import * from pytriqs.utility.h5diff import h5diff from pytriqs.gf import * from pytriqs.utility.comparison_tests import assert_block_gfs_are_close -from pytriqs.applications.dft import BlockStructure +from block_structure import BlockStructure SK = SumkDFT('blockstructure.in.h5',use_dft_blocks=True) diff --git a/test/hk_convert.py b/test/hk_convert.py index 439d457b..e1d72893 100644 --- a/test/hk_convert.py +++ b/test/hk_convert.py @@ -21,11 +21,12 @@ ################################################################################ -from pytriqs.applications.dft.converters import * from pytriqs.archive import * from pytriqs.utility.h5diff import h5diff import pytriqs.utility.mpi as mpi +from converters import * + Converter = HkConverter(filename='hk_convert_hamiltonian.hk',hdf_filename='hk_convert.out.h5') Converter.convert_dft_input() diff --git a/test/plovasp/atm/test_atm.py b/test/plovasp/atm/test_atm.py index 3e22b3f5..913fc40a 100644 --- a/test/plovasp/atm/test_atm.py +++ b/test/plovasp/atm/test_atm.py @@ -2,7 +2,7 @@ import os import numpy as np -from pytriqs.applications.dft.converters.plovasp.atm import dos_tetra_weights_3d +from converters.plovasp.atm import dos_tetra_weights_3d import mytest ################################################################################ diff --git a/test/plovasp/inpconf/test_general.py b/test/plovasp/inpconf/test_general.py index 8cc694de..14d04b3f 100644 --- a/test/plovasp/inpconf/test_general.py +++ b/test/plovasp/inpconf/test_general.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/inpconf/test_groups.py b/test/plovasp/inpconf/test_groups.py index 6f2a1cc2..b1d7153f 100644 --- a/test/plovasp/inpconf/test_groups.py +++ b/test/plovasp/inpconf/test_groups.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/inpconf/test_input.py b/test/plovasp/inpconf/test_input.py index 89418fdb..94941a19 100644 --- a/test/plovasp/inpconf/test_input.py +++ b/test/plovasp/inpconf/test_input.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/inpconf/test_parameter_set.py b/test/plovasp/inpconf/test_parameter_set.py index 36590dc6..c6748086 100644 --- a/test/plovasp/inpconf/test_parameter_set.py +++ b/test/plovasp/inpconf/test_parameter_set.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/inpconf/test_shells.py b/test/plovasp/inpconf/test_shells.py index 8d488481..98220d2b 100644 --- a/test/plovasp/inpconf/test_shells.py +++ b/test/plovasp/inpconf/test_shells.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/inpconf/test_special_parsers.py b/test/plovasp/inpconf/test_special_parsers.py index 9e8dab57..a751f480 100644 --- a/test/plovasp/inpconf/test_special_parsers.py +++ b/test/plovasp/inpconf/test_special_parsers.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import arraytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.inpconf import ConfigParameters ################################################################################ # diff --git a/test/plovasp/plotools/test_consistency.py b/test/plovasp/plotools/test_consistency.py index 9add6920..216e89f7 100644 --- a/test/plovasp/plotools/test_consistency.py +++ b/test/plovasp/plotools/test_consistency.py @@ -1,8 +1,8 @@ -import pytriqs.applications.dft.converters.plovasp.vaspio -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.plotools import check_data_consistency -from pytriqs.applications.dft.converters.plovasp.elstruct import ElectronicStructure +import converters.plovasp.vaspio +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.plotools import check_data_consistency +from converters.plovasp.elstruct import ElectronicStructure import mytest ################################################################################ diff --git a/test/plovasp/proj_group/test_block_map.py b/test/plovasp/proj_group/test_block_map.py index e7ab7993..80d6fd04 100644 --- a/test/plovasp/proj_group/test_block_map.py +++ b/test/plovasp/proj_group/test_block_map.py @@ -4,9 +4,9 @@ import rpath _rpath = os.path.dirname(rpath.__file__) + '/' import numpy as np -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.proj_shell import ProjectorShell -from pytriqs.applications.dft.converters.plovasp.proj_group import ProjectorGroup +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.proj_shell import ProjectorShell +from converters.plovasp.proj_group import ProjectorGroup import mytest ################################################################################ diff --git a/test/plovasp/proj_group/test_one_site.py b/test/plovasp/proj_group/test_one_site.py index 9a4939e0..8a777d10 100644 --- a/test/plovasp/proj_group/test_one_site.py +++ b/test/plovasp/proj_group/test_one_site.py @@ -4,11 +4,11 @@ import rpath _rpath = os.path.dirname(rpath.__file__) + '/' import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import VaspData -from pytriqs.applications.dft.converters.plovasp.elstruct import ElectronicStructure -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.proj_shell import ProjectorShell -from pytriqs.applications.dft.converters.plovasp.proj_group import ProjectorGroup +from converters.plovasp.vaspio import VaspData +from converters.plovasp.elstruct import ElectronicStructure +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.proj_shell import ProjectorShell +from converters.plovasp.proj_group import ProjectorGroup from pytriqs.archive import HDFArchive import mytest diff --git a/test/plovasp/proj_group/test_select_bands.py b/test/plovasp/proj_group/test_select_bands.py index f3bfb61f..4d53c42b 100644 --- a/test/plovasp/proj_group/test_select_bands.py +++ b/test/plovasp/proj_group/test_select_bands.py @@ -4,11 +4,11 @@ import rpath _rpath = os.path.dirname(rpath.__file__) + '/' import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import VaspData -from pytriqs.applications.dft.converters.plovasp.elstruct import ElectronicStructure -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.proj_shell import ProjectorShell -from pytriqs.applications.dft.converters.plovasp.proj_group import ProjectorGroup +from converters.plovasp.vaspio import VaspData +from converters.plovasp.elstruct import ElectronicStructure +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.proj_shell import ProjectorShell +from converters.plovasp.proj_group import ProjectorGroup import mytest ################################################################################ diff --git a/test/plovasp/proj_group/test_two_site.py b/test/plovasp/proj_group/test_two_site.py index 4f62961a..8db9b951 100644 --- a/test/plovasp/proj_group/test_two_site.py +++ b/test/plovasp/proj_group/test_two_site.py @@ -4,11 +4,11 @@ import rpath _rpath = os.path.dirname(rpath.__file__) + '/' import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import VaspData -from pytriqs.applications.dft.converters.plovasp.elstruct import ElectronicStructure -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.proj_shell import ProjectorShell -from pytriqs.applications.dft.converters.plovasp.proj_group import ProjectorGroup +from converters.plovasp.vaspio import VaspData +from converters.plovasp.elstruct import ElectronicStructure +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.proj_shell import ProjectorShell +from converters.plovasp.proj_group import ProjectorGroup from pytriqs.archive import HDFArchive import mytest diff --git a/test/plovasp/proj_shell/test_projshells.py b/test/plovasp/proj_shell/test_projshells.py index 41480649..97e1693f 100644 --- a/test/plovasp/proj_shell/test_projshells.py +++ b/test/plovasp/proj_shell/test_projshells.py @@ -4,11 +4,11 @@ import rpath _rpath = os.path.dirname(rpath.__file__) + '/' import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import VaspData -from pytriqs.applications.dft.converters.plovasp.elstruct import ElectronicStructure -from pytriqs.applications.dft.converters.plovasp.inpconf import ConfigParameters -from pytriqs.applications.dft.converters.plovasp.proj_shell import ProjectorShell -from pytriqs.applications.dft.converters.plovasp.proj_group import ProjectorGroup +from converters.plovasp.vaspio import VaspData +from converters.plovasp.elstruct import ElectronicStructure +from converters.plovasp.inpconf import ConfigParameters +from converters.plovasp.proj_shell import ProjectorShell +from converters.plovasp.proj_group import ProjectorGroup import mytest ################################################################################ diff --git a/test/plovasp/vaspio/test_doscar.py b/test/plovasp/vaspio/test_doscar.py index 2b22a5df..68148d75 100644 --- a/test/plovasp/vaspio/test_doscar.py +++ b/test/plovasp/vaspio/test_doscar.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import mytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import Doscar +from converters.plovasp.vaspio import Doscar ################################################################################ # diff --git a/test/plovasp/vaspio/test_eigenval.py b/test/plovasp/vaspio/test_eigenval.py index 8a4a17a9..4cca5a8d 100644 --- a/test/plovasp/vaspio/test_eigenval.py +++ b/test/plovasp/vaspio/test_eigenval.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import mytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import Eigenval +from converters.plovasp.vaspio import Eigenval ################################################################################ # diff --git a/test/plovasp/vaspio/test_kpoints.py b/test/plovasp/vaspio/test_kpoints.py index 4a70338b..43f67ef3 100644 --- a/test/plovasp/vaspio/test_kpoints.py +++ b/test/plovasp/vaspio/test_kpoints.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import mytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import Kpoints +from converters.plovasp.vaspio import Kpoints ################################################################################ # diff --git a/test/plovasp/vaspio/test_poscar.py b/test/plovasp/vaspio/test_poscar.py index c0047b0e..25d37080 100644 --- a/test/plovasp/vaspio/test_poscar.py +++ b/test/plovasp/vaspio/test_poscar.py @@ -7,7 +7,7 @@ _rpath = os.path.dirname(rpath.__file__) + '/' import mytest import numpy as np -from pytriqs.applications.dft.converters.plovasp.vaspio import Poscar +from converters.plovasp.vaspio import Poscar ################################################################################ # diff --git a/test/sigma_from_file.py b/test/sigma_from_file.py index 7f8640c0..ccf88280 100644 --- a/test/sigma_from_file.py +++ b/test/sigma_from_file.py @@ -22,7 +22,7 @@ from pytriqs.archive import * from pytriqs.gf import * from pytriqs.gf.tools import * -from pytriqs.applications.dft.sumk_dft_tools import * +from sumk_dft_tools import * from pytriqs.utility.comparison_tests import * import numpy as np diff --git a/test/srvo3_Gloc.py b/test/srvo3_Gloc.py index 20f9d120..f10555e4 100644 --- a/test/srvo3_Gloc.py +++ b/test/srvo3_Gloc.py @@ -21,8 +21,8 @@ from pytriqs.archive import * from pytriqs.gf import * -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.converters.wien2k_converter import * +from sumk_dft import * +from converters.wien2k_converter import * from pytriqs.operators.util import set_operator_structure from pytriqs.utility.comparison_tests import * from pytriqs.utility.h5diff import h5diff diff --git a/test/srvo3_transp.py b/test/srvo3_transp.py index 920459f0..cb609c2f 100644 --- a/test/srvo3_transp.py +++ b/test/srvo3_transp.py @@ -20,9 +20,9 @@ ################################################################################ from numpy import * -from pytriqs.applications.dft.converters.wien2k_converter import * -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.sumk_dft_tools import * +from converters.wien2k_converter import * +from sumk_dft import * +from sumk_dft_tools import * from pytriqs.utility.comparison_tests import * from pytriqs.utility.h5diff import h5diff diff --git a/test/sumkdft_basic.py b/test/sumkdft_basic.py index ba456060..52dd1a48 100644 --- a/test/sumkdft_basic.py +++ b/test/sumkdft_basic.py @@ -21,7 +21,7 @@ ################################################################################ from pytriqs.archive import * -from pytriqs.applications.dft.sumk_dft_tools import SumkDFTTools +from sumk_dft_tools import SumkDFTTools import pytriqs.utility.mpi as mpi from pytriqs.utility.comparison_tests import * from pytriqs.utility.h5diff import h5diff diff --git a/test/w90_convert.py b/test/w90_convert.py index e5c18ffd..1c483e50 100644 --- a/test/w90_convert.py +++ b/test/w90_convert.py @@ -21,7 +21,7 @@ ################################################################################ -from pytriqs.applications.dft.converters import * +from converters import * from pytriqs.archive import * from pytriqs.utility.h5diff import h5diff import pytriqs.utility.mpi as mpi diff --git a/test/wien2k_convert.py b/test/wien2k_convert.py index c643f19a..77076068 100644 --- a/test/wien2k_convert.py +++ b/test/wien2k_convert.py @@ -21,11 +21,12 @@ ################################################################################ from pytriqs.archive import * -from pytriqs.applications.dft.converters import Wien2kConverter from pytriqs.utility.comparison_tests import * from pytriqs.utility.h5diff import h5diff import pytriqs.utility.mpi as mpi +from converters import Wien2kConverter + Converter = Wien2kConverter(filename='SrVO3') Converter.hdf_file = 'wien2k_convert.out.h5' Converter.convert_dft_input() From a88ea9c469b5d798ccc78151f001d14bdaa51177 Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Mon, 22 Jan 2018 17:49:04 -0500 Subject: [PATCH 08/44] Fix but 2 tests - inpconf due to a silly string comparion issue - vaspio ?? --- test/plovasp/CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/plovasp/CMakeLists.txt b/test/plovasp/CMakeLists.txt index 11669c67..57e6877c 100644 --- a/test/plovasp/CMakeLists.txt +++ b/test/plovasp/CMakeLists.txt @@ -1,5 +1,5 @@ # load triqs helper to set up tests -set(TestSuites +set(all_tests inpconf # plocar_io plotools @@ -8,10 +8,11 @@ set(TestSuites vaspio atm) -FILE(COPY ${TestSuites} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +FILE(COPY ${all_tests} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) FILE(COPY run_suite.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -foreach(test_suite ${TestSuites}) - add_test(${test_suite} - ${PythonBuildExecutable} run_suite.py ${test_suite}) -endforeach(test_suite ${TestSuites}) +foreach(t ${all_tests}) + add_test(NAME ${t} COMMAND python run_suite.py ${t}) +endforeach() + +set_property(TEST ${all_tests} PROPERTY ENVIRONMENT PYTHONPATH=${CMAKE_BINARY_DIR}/python:$ENV{PYTHONPATH} ) From ef9f37e01713edd71209cd32fb5063db06573822 Mon Sep 17 00:00:00 2001 From: Manuel Date: Mon, 22 Jan 2018 20:29:53 -0500 Subject: [PATCH 09/44] Add C --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97c6d461..fbd1525d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ message( STATUS "-------- BUILD-TYPE: ${CMAKE_BUILD_TYPE} -------------") # start configuration cmake_minimum_required(VERSION 2.8) -project(dft_tools CXX Fortran) +project(dft_tools C CXX Fortran) # Use shared libraries set(BUILD_SHARED_LIBS ON) From ca16e77d22cc7aecbd5cd83500227e81bb45de8a Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Fri, 2 Feb 2018 15:56:08 +0100 Subject: [PATCH 10/44] [cmake] Fixing CMakeLists.txt for documentation --- CMakeLists.txt | 2 +- doc/CMakeLists.txt | 34 ++++++++++++++-------------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbd1525d..fbc0b81a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ endif() #------------------------ option(BUILD_DOC "Build documentation" OFF) if(${BUILD_DOC}) - if(NOT TRIQS_WITH_DOCUMENTATION) + if(NOT ${TRIQS_WITH_DOCUMENTATION}) message("Error: TRIQS library has not been compiled with its documentation") endif() add_subdirectory(doc) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 54487abf..01597803 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,29 +1,23 @@ # generate the conf.py -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) -# all rst files of the documentation -file(GLOB_RECURSE doc_sources *.rst) +# --------------------------------- +# Top Sphinx target +# --------------------------------- +# Sources +file(GLOB_RECURSE sources *.rst) # create documentation target set(sphinx_top ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) -add_custom_command(OUTPUT ${sphinx_top} DEPENDS ${doc_sources} py_copy - COMMAND ${CMAKE_BINARY_DIR}/build_pytriqs ${TRIQS_SPHINXBUILD_EXECUTABLE} -c . -b html ${CMAKE_CURRENT_SOURCE_DIR} html) -add_custom_target(doc_sphinx ALL DEPENDS ${sphinx_top}) +add_custom_command(OUTPUT ${sphinx_top} DEPENDS ${sources} + COMMAND ${TRIQS_SPHINXBUILD_EXECUTABLE} -c . -j8 -b html ${CMAKE_CURRENT_BINARY_DIR} html) +add_custom_target(doc_sphinx ALL DEPENDS ${sphinx_top} ${CMAKE_CURRENT_BINARY_DIR}) -# install +# --------------------------------- +# Install +# --------------------------------- install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ COMPONENT documentation DESTINATION share/doc/dft_tools - FILES_MATCHING - PATTERN "*.html" - PATTERN "*.png" - PATTERN "*.js" + FILES_MATCHING + REGEX "\\.(html|pdf|png|gif|jpg|js|xsl|css|py|txt|inv|bib)$" PATTERN "_*" - PATTERN "*.jpg" - PATTERN "*.gif" - PATTERN "*.xsl" - PATTERN "*.css" - PATTERN "*.pdf" - PATTERN "*.py" - PATTERN "*.txt" - PATTERN "*.inv" - PATTERN "*.bib" ) From 1158e2caccb93e102fda167d52c70faac9f9864a Mon Sep 17 00:00:00 2001 From: Manuel Date: Tue, 6 Feb 2018 16:44:11 -0500 Subject: [PATCH 11/44] Fix installation of python sources in CMakeLists --- python/CMakeLists.txt | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 3e481102..e69d8dd0 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,25 +1,20 @@ # where will the python end up in triqs? -set(python_destination pytriqs/applications/dft) -set(PYTHON_LIB_DEST ${CPP2PY_PYTHON_LIB_DEST_ROOT}/pytriqs/cthyb) +set(PYTHON_LIB_DEST ${CPP2PY_PYTHON_LIB_DEST_ROOT}/triqs_dft_tools) # site_customize for build -set(package_name "pytriqs.applications") +set(package_name "triqs_dft_tools") # Create a temporary copy of the python modules so that we can run before installation with the test -FILE(GLOB_RECURSE all_py_files RELATIVE ${CMAKE_SOURCE_DIR}/python *.py ) -foreach(f ${all_py_files}) +FILE(GLOB_RECURSE PYTHON_SOURCES RELATIVE ${CMAKE_SOURCE_DIR}/python *.py ) +foreach(f ${PYTHON_SOURCES}) configure_file(${f} ${f} COPYONLY) endforeach() -#configure_file(${CMAKE_SOURCE_DIR}/cmake/sitecustomize.py ${CMAKE_CURRENT_BINARY_DIR}/sitecustomize.py @ONLY) - # VASP converter add_subdirectory(converters/plovasp) # add version file configure_file(version.py.in version.py @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.py DESTINATION ${PYTHON_LIB_DEST}) - - - +# install files +install(FILES ${PYTHON_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/version.py DESTINATION ${PYTHON_LIB_DEST}) From 64a45510c802ce057f945703883cf7a2d8def8a1 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Mon, 12 Feb 2018 14:11:41 -0500 Subject: [PATCH 12/44] [jenkins] add triqs-docker-based linux builds --- .dockerignore | 3 +++ Dockerfile | 10 ++++++++++ Jenkinsfile | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Jenkinsfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..f6f7fc8a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +Dockerfile +Jenkinsfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..704e29a7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +# See ../triqs/packaging for other options +FROM flatironinstitute/triqs:master-ubuntu-clang + +COPY . ${SRC}/dft_tools +WORKDIR ${BUILD}/dft_tools +RUN chown build . +USER build +RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} && make -j2 && make test +USER root +RUN make install diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..76333733 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,34 @@ +properties([ + disableConcurrentBuilds(), + pipelineTriggers([ + upstream( + threshold: 'SUCCESS', + upstreamProjects: '/TRIQS/triqs/' + env.BRANCH_NAME.replaceAll('/', '%2F') + ) + ]) +]) + +def platforms = [:] + +def dockerPlatforms = ["ubuntu-clang", "ubuntu-gcc", "centos-gcc"] +for (int i = 0; i < dockerPlatforms.size(); i++) { + def platform = dockerPlatforms[i] + platforms[platform] = { -> + stage(platform) { + timeout(time: 1, unit: 'HOURS') { + node('docker') { + checkout scm + /* construct a Dockerfile for this base */ + sh ''' + ( echo "FROM flatironinstitute/triqs:$BRANCH_NAME-$STAGE_NAME" ; sed '0,/^FROM /d' Dockerfile ) > Dockerfile.jenkins + mv -f Dockerfile.jenkins Dockerfile + ''' + /* build and tag */ + def img = docker.build("flatironinstitute/dft_tools:${env.BRANCH_NAME}-${env.STAGE_NAME}") + } + } + } + } +} + +parallel platforms From 91ce2eef4bd41b28889fa2ec4dc8f3e47eca1ed1 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Tue, 13 Feb 2018 15:42:09 -0500 Subject: [PATCH 13/44] Fix use of numpy.full on older numpy Was failing test srvo3_transp on centos: File "/home/build/dft_tools/python/sumk_dft_tools.py", line 947, in for direction in self.directions} AttributeError: 'module' object has no attribute 'full' --- python/sumk_dft_tools.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/sumk_dft_tools.py b/python/sumk_dft_tools.py index 46ead06c..98d1af7a 100644 --- a/python/sumk_dft_tools.py +++ b/python/sumk_dft_tools.py @@ -28,6 +28,9 @@ from sumk_dft import SumkDFT from scipy.integrate import * from scipy.interpolate import * +if not hasattr(numpy, 'full'): + # polyfill full for older numpy: + numpy.full = lambda a, f: numpy.zeros(a) + f class SumkDFTTools(SumkDFT): """ From 586958eea9e78236e0438313cb3316d77f4aece1 Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Wed, 14 Feb 2018 16:17:19 -0500 Subject: [PATCH 14/44] Fixing install of python files after cmake changes --- python/CMakeLists.txt | 7 +++---- python/converters/CMakeLists.txt | 10 ++++++++++ python/converters/plovasp/CMakeLists.txt | 19 ++++++++++++------- 3 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 python/converters/CMakeLists.txt diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e69d8dd0..2ad35566 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -5,16 +5,15 @@ set(PYTHON_LIB_DEST ${CPP2PY_PYTHON_LIB_DEST_ROOT}/triqs_dft_tools) set(package_name "triqs_dft_tools") # Create a temporary copy of the python modules so that we can run before installation with the test -FILE(GLOB_RECURSE PYTHON_SOURCES RELATIVE ${CMAKE_SOURCE_DIR}/python *.py ) +FILE(GLOB PYTHON_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.py ) foreach(f ${PYTHON_SOURCES}) configure_file(${f} ${f} COPYONLY) endforeach() -# VASP converter -add_subdirectory(converters/plovasp) - # add version file configure_file(version.py.in version.py @ONLY) # install files install(FILES ${PYTHON_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/version.py DESTINATION ${PYTHON_LIB_DEST}) + +add_subdirectory(converters) diff --git a/python/converters/CMakeLists.txt b/python/converters/CMakeLists.txt new file mode 100644 index 00000000..3c719f26 --- /dev/null +++ b/python/converters/CMakeLists.txt @@ -0,0 +1,10 @@ +# Create a temporary copy of the python modules so that we can run before installation with the test +FILE(GLOB PYTHON_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.py) +foreach(f ${PYTHON_SOURCES}) + configure_file(${f} ${f} COPYONLY) +endforeach() + +# install files +install(FILES ${PYTHON_SOURCES} DESTINATION ${PYTHON_LIB_DEST}/converters) + +add_subdirectory(plovasp) diff --git a/python/converters/plovasp/CMakeLists.txt b/python/converters/plovasp/CMakeLists.txt index f9750662..9f2fbdaa 100644 --- a/python/converters/plovasp/CMakeLists.txt +++ b/python/converters/plovasp/CMakeLists.txt @@ -1,14 +1,19 @@ -set(python_destination pytriqs/applications/dft/converters/plovasp) - +# === Build and install atm module add_cpp2py_module(atm) target_link_libraries(atm atm_c triqs) -#triqs_set_rpath_for_target(atm) target_compile_options(atm PRIVATE -std=c++17) target_include_directories(atm PRIVATE ${CMAKE_SOURCE_DIR}/c++) +install(TARGETS atm DESTINATION ${PYTHON_LIB_DEST}/converters/plovasp) + +# === Copy Python files to current build directory and register for install +set(PYTHON_SOURCES __init__.py converter.py elstruct.py inpconf.py plotools.py proj_group.py proj_shell.py sc_dmft.py vaspio.py) +foreach(f ${PYTHON_SOURCES}) + configure_file(${f} ${f} COPYONLY) +endforeach() + +# install files +install(FILES ${PYTHON_SOURCES} DESTINATION ${PYTHON_LIB_DEST}/converters/plovasp) + # This we need in order for tests to work #add_custom_command(TARGET atm POST_BUILD COMMAND ln -fs ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}/atm.so ${CMAKE_BINARY_DIR}/python/dft/converters/plovasp) - -install (TARGETS atm DESTINATION ${PYTHON_LIB_DEST}) - - From d7df10d95d2a661e3a2af8e17e3884e228e982f7 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Wed, 14 Feb 2018 16:35:07 -0500 Subject: [PATCH 15/44] [jenkins] add osx builds using triqs zip artifact --- Jenkinsfile | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 76333733..f3791c8d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,9 +1,12 @@ +def triqsProject = '/TRIQS/triqs/' + env.BRANCH_NAME.replaceAll('/', '%2F') + properties([ disableConcurrentBuilds(), + buildDiscarder(logRotator(numToKeepStr: '10', daysToKeepStr: '30')), pipelineTriggers([ upstream( threshold: 'SUCCESS', - upstreamProjects: '/TRIQS/triqs/' + env.BRANCH_NAME.replaceAll('/', '%2F') + upstreamProjects: triqsProject ) ]) ]) @@ -31,4 +34,54 @@ for (int i = 0; i < dockerPlatforms.size(); i++) { } } +def osxPlatforms = [ + ["gcc", ['CC=gcc-7', 'CXX=g++-7']], + ["clang", ['CC=/usr/local/opt/llvm/bin/clang', 'CXX=/usr/local/opt/llvm/bin/clang++', 'CXXFLAGS=-I/usr/local/opt/llvm/include', 'LDFLAGS=-L/usr/local/opt/llvm/lib']] +] +for (int i = 0; i < osxPlatforms.size(); i++) { + def platformEnv = osxPlatforms[i] + def platform = platformEnv[0] + platforms["osx-$platform"] = { -> + stage("osx-$platform") { + timeout(time: 1, unit: 'HOURS') { + node('osx && triqs') { + def workDir = pwd() + def tmpDir = pwd(tmp:true) + def buildDir = "$tmpDir/build" + def installDir = "$tmpDir/install" + + dir(installDir) { + deleteDir() + } + + copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") + unzip(zipFile: "osx-${platform}.zip", dir: installDir) + /* fixup zip-stripped permissions (JENKINS-13128) */ + sh "chmod +x $installDir/bin/*" + + checkout scm + + dir(buildDir) { withEnv(platformEnv[1]+[ + "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", + "CPATH=$installDir/include", + "LIBRARY_PATH=$installDir/lib", + "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { + deleteDir() + sh "cmake $workDir -DTRIQS_ROOT=$installDir" + sh "make -j2" + try { + sh "make test" + } catch (exc) { + archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log') + throw exc + } + sh "make install" + } } + // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) + } + } + } + } +} + parallel platforms From 4dc6aa513b210efdb4c9460a7d6dd2cb7aee5f20 Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Thu, 22 Feb 2018 12:02:22 +0100 Subject: [PATCH 16/44] [Tests] Remove spaces for string comparison due to different Osx Output format --- test/plovasp/inpconf/test_input.py | 14 ++++++++------ test/plovasp/vaspio/mytest.py | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/test/plovasp/inpconf/test_input.py b/test/plovasp/inpconf/test_input.py index 94941a19..9766ea1e 100644 --- a/test/plovasp/inpconf/test_input.py +++ b/test/plovasp/inpconf/test_input.py @@ -75,14 +75,15 @@ class TestParseInput(arraytest.ArrayTestCase): res += conf_pars.shells.__repr__() + '\n\n' res += "Groups:\n" res += conf_pars.groups.__repr__() + res = res.replace(" ","") # Remove spaces for comparison expected = r"""Shells: -[{'ion_list': array([4, 5, 6, 7]), 'user_index': 1, 'lshell': 2}, {'tmatrix': array([[ 0., 1., 0.], - [ 1., 0., 0.], - [ 0., 0., 1.]]), 'ion_list': array([0, 1, 2, 3]), 'user_index': 2, 'lshell': 1}, {'ion_list': array([0, 1, 2, 3]), 'user_index': 3, 'lshell': 3}] +[{'ion_list':array([4,5,6,7]),'user_index':1,'lshell':2},{'tmatrix':array([[0.,1.,0.], +[1.,0.,0.], +[0.,0.,1.]]),'ion_list':array([0,1,2,3]),'user_index':2,'lshell':1},{'ion_list':array([0,1,2,3]),'user_index':3,'lshell':3}] Groups: -[{'normalize': True, 'index': 1, 'ewindow': (-7.6, 3.0), 'normion': True, 'shells': [0, 1]}, {'normalize': True, 'index': 2, 'ewindow': (-1.6, 2.0), 'normion': True, 'shells': [2]}]""" +[{'normalize':True,'index':1,'ewindow':(-7.6,3.0),'normion':True,'shells':[0,1]},{'normalize':True,'index':2,'ewindow':(-1.6,2.0),'normion':True,'shells':[2]}]""" self.assertEqual(res, expected) @@ -99,12 +100,13 @@ Groups: res += conf_pars.shells.__repr__() + '\n\n' res += "Groups:\n" res += conf_pars.groups.__repr__() + res = res.replace(" ","") # Remove spaces for comparison expected = r"""Shells: -[{'ion_list': array([4, 5, 6, 7]), 'user_index': 1, 'lshell': 2}] +[{'ion_list':array([4,5,6,7]),'user_index':1,'lshell':2}] Groups: -[{'normalize': True, 'index': '1', 'ewindow': (-7.6, 3.0), 'shells': [0], 'normion': True}]""" +[{'normalize':True,'index':'1','ewindow':(-7.6,3.0),'shells':[0],'normion':True}]""" self.assertEqual(res, expected) diff --git a/test/plovasp/vaspio/mytest.py b/test/plovasp/vaspio/mytest.py index fb0c64e8..f92cba6d 100644 --- a/test/plovasp/vaspio/mytest.py +++ b/test/plovasp/vaspio/mytest.py @@ -45,7 +45,9 @@ class MyTestCase(unittest.TestCase): # # Remove empty lines lstr1 = filter(lambda s: s.strip() != '', str1.splitlines(True)) + lstr1 = [str1.replace(" ","") for str1 in lstr1] # Remove spaces lstr2 = filter(lambda s: s.strip() != '', str2.splitlines(True)) + lstr2 = [str2.replace(" ","") for str2 in lstr2] # Remove spaces # diff delta = difflib.unified_diff(lstr1, lstr2) # combine delta's to a string From 0a84f48e438a72046de148103016f375c179f463 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Thu, 22 Feb 2018 14:16:45 -0500 Subject: [PATCH 17/44] [jenkins] Build PRs against upstream target branch cleanup unused image tags; may want to switch away from Dockerfile to an explicit container run at some point. --- Jenkinsfile | 99 ++++++++++++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f3791c8d..6ea10bd9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,5 @@ -def triqsProject = '/TRIQS/triqs/' + env.BRANCH_NAME.replaceAll('/', '%2F') +def triqsBranch = env.CHANGE_TARGET ?: env.BRANCH_NAME +def triqsProject = '/TRIQS/triqs/' + triqsBranch.replaceAll('/', '%2F') properties([ disableConcurrentBuilds(), @@ -16,22 +17,22 @@ def platforms = [:] def dockerPlatforms = ["ubuntu-clang", "ubuntu-gcc", "centos-gcc"] for (int i = 0; i < dockerPlatforms.size(); i++) { def platform = dockerPlatforms[i] - platforms[platform] = { -> - stage(platform) { - timeout(time: 1, unit: 'HOURS') { - node('docker') { - checkout scm - /* construct a Dockerfile for this base */ - sh ''' - ( echo "FROM flatironinstitute/triqs:$BRANCH_NAME-$STAGE_NAME" ; sed '0,/^FROM /d' Dockerfile ) > Dockerfile.jenkins - mv -f Dockerfile.jenkins Dockerfile - ''' - /* build and tag */ - def img = docker.build("flatironinstitute/dft_tools:${env.BRANCH_NAME}-${env.STAGE_NAME}") - } + platforms[platform] = { -> stage(platform) { + timeout(time: 1, unit: 'HOURS') { + node('docker') { + checkout scm + /* construct a Dockerfile for this base */ + sh """ + ( echo "FROM flatironinstitute/triqs:${triqsBranch}-${env.STAGE_NAME}" ; sed '0,/^FROM /d' Dockerfile ) > Dockerfile.jenkins + mv -f Dockerfile.jenkins Dockerfile + """ + /* build and tag */ + def img = docker.build("flatironinstitute/dft_tools:${env.BRANCH_NAME}-${env.STAGE_NAME}") + /* but we don't need the tag so clean it up (alternatively, could refacter to run in container) */ + sh "docker rmi ${img.imageName()}" } } - } + } } } def osxPlatforms = [ @@ -41,47 +42,45 @@ def osxPlatforms = [ for (int i = 0; i < osxPlatforms.size(); i++) { def platformEnv = osxPlatforms[i] def platform = platformEnv[0] - platforms["osx-$platform"] = { -> - stage("osx-$platform") { - timeout(time: 1, unit: 'HOURS') { - node('osx && triqs') { - def workDir = pwd() - def tmpDir = pwd(tmp:true) - def buildDir = "$tmpDir/build" - def installDir = "$tmpDir/install" + platforms["osx-$platform"] = { -> stage("osx-$platform") { + timeout(time: 1, unit: 'HOURS') { + node('osx && triqs') { + def srcDir = pwd() + def tmpDir = pwd(tmp:true) + def buildDir = "$tmpDir/build" + def installDir = "$tmpDir/install" - dir(installDir) { - deleteDir() - } + dir(installDir) { + deleteDir() + } - copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") - unzip(zipFile: "osx-${platform}.zip", dir: installDir) - /* fixup zip-stripped permissions (JENKINS-13128) */ - sh "chmod +x $installDir/bin/*" + copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") + unzip(zipFile: "osx-${platform}.zip", dir: installDir) + /* fixup zip-stripped permissions (JENKINS-13128) */ + sh "chmod +x $installDir/bin/*" - checkout scm + checkout scm - dir(buildDir) { withEnv(platformEnv[1]+[ - "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", - "CPATH=$installDir/include", - "LIBRARY_PATH=$installDir/lib", - "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { - deleteDir() - sh "cmake $workDir -DTRIQS_ROOT=$installDir" - sh "make -j2" - try { - sh "make test" - } catch (exc) { - archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log') - throw exc - } - sh "make install" - } } - // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) - } + dir(buildDir) { withEnv(platformEnv[1]+[ + "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", + "CPATH=$installDir/include", + "LIBRARY_PATH=$installDir/lib", + "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { + deleteDir() + sh "cmake $srcDir -DTRIQS_ROOT=$installDir" + sh "make -j2" + try { + sh "make test" + } catch (exc) { + archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log') + throw exc + } + sh "make install" + } } + // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) } } - } + } } } parallel platforms From 1a4f161ea4f28378c23172625cd14f561c2207f7 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Thu, 22 Feb 2018 17:48:32 -0500 Subject: [PATCH 18/44] [jenkins] Add email alerts on failure --- Jenkinsfile | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6ea10bd9..fbfa59bc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -83,4 +83,31 @@ for (int i = 0; i < osxPlatforms.size(); i++) { } } } -parallel platforms +try { + parallel platforms +} catch (err) { + emailext( + subject: "\$PROJECT_NAME - Build # \$BUILD_NUMBER - FAILED", + body: """\$PROJECT_NAME - Build # \$BUILD_NUMBER - FAILED + +$err + +Check console output at \$BUILD_URL to view full results. + +Building \$BRANCH_NAME for \$CAUSE +\$JOB_DESCRIPTION + +Chages: +\$CHANGES + +End of build log: +\${BUILD_LOG,maxLines=60} + """, + to: 'mzingl@flatironinstitute.org, hstrand@flatironinstitute.org, nils.wentzell@gmail.com, dsimon@flatironinstitute.org', + recipientProviders: [ + [$class: 'DevelopersRecipientProvider'], + ], + replyTo: '$DEFAULT_REPLYTO' + ) + throw err +} From 7599336e558c34a33bfe54f9035d55c79aecb352 Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Fri, 23 Feb 2018 10:30:16 +0100 Subject: [PATCH 19/44] Fixed a bug in reading scale from POSCAR in PLOVasp --- python/converters/plovasp/vaspio.py | 2 +- test/plovasp/vaspio/POSCAR.example.out | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/converters/plovasp/vaspio.py b/python/converters/plovasp/vaspio.py index ad268de8..f460b61a 100644 --- a/python/converters/plovasp/vaspio.py +++ b/python/converters/plovasp/vaspio.py @@ -363,7 +363,7 @@ class Poscar: # Read scale sline = readline_remove_comments() - ascale = float(sline[0]) + ascale = float(sline) # Read lattice vectors self.a_brav = np.zeros((3, 3)) for ia in xrange(3): diff --git a/test/plovasp/vaspio/POSCAR.example.out b/test/plovasp/vaspio/POSCAR.example.out index b0d1a9d7..4acafc5e 100644 --- a/test/plovasp/vaspio/POSCAR.example.out +++ b/test/plovasp/vaspio/POSCAR.example.out @@ -3,8 +3,8 @@ ntypes = 1 nions = [1] el_names = ['V'] a_brav: -[[-1. 1. 1.] - [ 1. -1. 1.] - [ 1. 1. -1.]] +[[-1.4939 1.4939 1.4939] + [ 1.4939 -1.4939 1.4939] + [ 1.4939 1.4939 -1.4939]] q_types: [array([[ 0., 0., 0.]])] From ad2ee87bc7123d222d5fd00e71a7d77cb0eeb438 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Thu, 22 Feb 2018 14:51:18 +0100 Subject: [PATCH 20/44] add deg_shells to block_structure --- python/block_structure.py | 61 +++++++++++++++++++++------------------ python/sumk_dft.py | 6 ++++ 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/python/block_structure.py b/python/block_structure.py index b0903161..f55cdba5 100644 --- a/python/block_structure.py +++ b/python/block_structure.py @@ -7,7 +7,7 @@ from warnings import warn class BlockStructure(object): """ Contains information about the Green function structure. - This class contains information about the structure of the solver + This class contains information about the structure of the solver and sumk Green functions and the mapping between them. Parameters @@ -33,19 +33,21 @@ class BlockStructure(object): solver_to_sumk_block : list of dict solver_to_sumk_block[ish][from_block] = to_block - maps from the solver block to the sumk block + maps from the solver block to the sumk block for *inequivalent* correlated shell ish """ def __init__(self,gf_struct_sumk=None, gf_struct_solver=None, solver_to_sumk=None, sumk_to_solver=None, - solver_to_sumk_block=None): + solver_to_sumk_block=None, + deg_shells=None): self.gf_struct_sumk = gf_struct_sumk self.gf_struct_solver = gf_struct_solver self.solver_to_sumk = solver_to_sumk self.sumk_to_solver = sumk_to_solver self.solver_to_sumk_block = solver_to_sumk_block + self.deg_shells = deg_shells @classmethod def full_structure(cls,gf_struct,corr_to_inequiv): @@ -99,20 +101,21 @@ class BlockStructure(object): gf_struct_sumk = gs_sumk_all, solver_to_sumk = copy.deepcopy(solver_to_sumk), sumk_to_solver = solver_to_sumk, - solver_to_sumk_block = s2sblock) + solver_to_sumk_block = s2sblock, + deg_shells = [[] for ish in range(len(gf_struct))]) def pick_gf_struct_solver(self,new_gf_struct): - """ Pick selected orbitals within blocks. + """ Pick selected orbitals within blocks. This throws away parts of the Green's function that (for some - reason - be sure that you know what you're doing) shouldn't be + reason - be sure that you know what you're doing) shouldn't be included in the calculation. To drop an entire block, just don't include it. To drop a certain index within a block, just don't include it. - If it was before: - + If it was before: + [{'up':[0,1],'down':[0,1],'left':[0,1]}] to choose the 0th index of the up block and the 1st index of @@ -130,11 +133,11 @@ class BlockStructure(object): Parameters ---------- new_gf_struct : list of dict - formatted the same as gf_struct_solver: + formatted the same as gf_struct_solver: new_gf_struct[ish][block]=list of indices in that block. """ - + for ish in range(len(self.gf_struct_solver)): gf_struct = new_gf_struct[ish] @@ -154,24 +157,24 @@ class BlockStructure(object): new_ind = gf_struct[blk].index(ind) self.sumk_to_solver[ish][k]=(blk,new_ind) else: - self.sumk_to_solver[ish][k]=(None,None) + self.sumk_to_solver[ish][k]=(None,None) # reindexing gf_struct so that it starts with 0 for k in gf_struct: gf_struct[k]=range(len(gf_struct[k])) self.gf_struct_solver[ish]=gf_struct def pick_gf_struct_sumk(self,new_gf_struct): - """ Pick selected orbitals within blocks. + """ Pick selected orbitals within blocks. This throws away parts of the Green's function that (for some - reason - be sure that you know what you're doing) shouldn't be + reason - be sure that you know what you're doing) shouldn't be included in the calculation. To drop an entire block, just don't include it. To drop a certain index within a block, just don't include it. - If it was before: - + If it was before: + [{'up':[0,1],'down':[0,1],'left':[0,1]}] to choose the 0th index of the up block and the 1st index of @@ -188,11 +191,11 @@ class BlockStructure(object): Parameters ---------- new_gf_struct : list of dict - formatted the same as gf_struct_solver: + formatted the same as gf_struct_solver: new_gf_struct[ish][block]=list of indices in that block. - However, the indices are not according to the solver Gf + However, the indices are not according to the solver Gf but the sumk Gf. """ @@ -218,7 +221,7 @@ class BlockStructure(object): Parameters ---------- mapping : list of dict - the dict consists of elements + the dict consists of elements (from_block,from_index) : (to_block,to_index) that maps from one structure to the other """ @@ -254,7 +257,7 @@ class BlockStructure(object): def create_gf(self,ish=0,gf_function=GfImFreq,**kwargs): """ Create a zero BlockGf having the gf_struct_solver structure. - When using GfImFreq as gf_function, typically you have to + When using GfImFreq as gf_function, typically you have to supply beta as keyword argument. Parameters @@ -284,7 +287,7 @@ class BlockStructure(object): .. warning:: Elements that are zero in the new structure due to - the new block structure will be just ignored, thus + the new block structure will be just ignored, thus approximated to zero. Parameters @@ -292,11 +295,11 @@ class BlockStructure(object): G : BlockGf the Gf that should be converted G_struct : GfStructure - the structure ofthat G + the structure of that G ish : int shell index show_warnings : bool - whether to show warnings when elements of the Green's + whether to show warnings when elements of the Green's function get thrown away **kwargs : options passed to the constructor for the new Gf @@ -325,8 +328,8 @@ class BlockStructure(object): return G_new def approximate_as_diagonal(self): - """ Create a structure for a GF with zero off-diagonal elements. - + """ Create a structure for a GF with zero off-diagonal elements. + .. warning:: In general, this will throw away non-zero elements of the @@ -361,7 +364,7 @@ class BlockStructure(object): if not compare(x,y): return False return True - elif isinstance(one,int): + elif isinstance(one,int): return one==two elif isinstance(one,str): return one==two @@ -375,7 +378,7 @@ class BlockStructure(object): warn('Cannot compare {}'.format(type(one))) return False - for prop in [ "gf_struct_sumk", "gf_struct_solver", + for prop in [ "gf_struct_sumk", "gf_struct_solver", "solver_to_sumk", "sumk_to_solver", "solver_to_sumk_block"]: if not compare(getattr(self,prop),getattr(other,prop)): return False @@ -388,8 +391,8 @@ class BlockStructure(object): """ Reduce to dict for HDF5 export.""" ret = {} - for element in [ "gf_struct_sumk", "gf_struct_solver", - "solver_to_sumk_block"]: + for element in [ "gf_struct_sumk", "gf_struct_solver", + "solver_to_sumk_block","deg_shells"]: ret[element] = getattr(self,element) def construct_mapping(mapping): @@ -436,6 +439,8 @@ class BlockStructure(object): keys = sorted(element[ish].keys(),key=keyfun) for k in keys: s+=' '+str(k)+str(element[ish][k])+'\n' + + s+= "deg_shells "+str( self.deg_shells)+'\n' return s from pytriqs.archive.hdf_archive_schemes import register_class diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 900faff5..b354704c 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1610,3 +1610,9 @@ class SumkDFT(object): def __set_solver_to_sumk_block(self,value): self.block_structure.solver_to_sumk_block = value solver_to_sumk_block = property(__get_solver_to_sumk_block,__set_solver_to_sumk_block) + + def __get_deg_shells(self): + return self.block_structure.deg_shells + def __set_deg_shells(self,value): + self.block_structure.deg_shells = value + deg_shells = property(__get_deg_shells,__set_deg_shells) From c1daf2f7893d8fc3ebe22218a7d882866203ca44 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Thu, 22 Feb 2018 17:49:55 +0100 Subject: [PATCH 21/44] BlockStructure: show warnings only when above threshold --- python/block_structure.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/python/block_structure.py b/python/block_structure.py index f55cdba5..a3f1b312 100644 --- a/python/block_structure.py +++ b/python/block_structure.py @@ -2,6 +2,7 @@ import copy import numpy as np from pytriqs.gf import GfImFreq, BlockGf from ast import literal_eval +import pytriqs.utility.mpi as mpi from warnings import warn class BlockStructure(object): @@ -298,12 +299,21 @@ class BlockStructure(object): the structure of that G ish : int shell index - show_warnings : bool + show_warnings : bool or float whether to show warnings when elements of the Green's function get thrown away + if float, set the threshold for the magnitude of an element + about to be thrown away to trigger a warning + (default: 1.e-10) **kwargs : options passed to the constructor for the new Gf """ + + warning_threshold = 1.e-10 + if isinstance(show_warnings, float): + warning_threshold = show_warnings + show_warnings = True + G_new = self.create_gf(ish=ish,**kwargs) for block in G_struct.gf_struct_solver[ish].keys(): for i1 in G_struct.gf_struct_solver[ish][block]: @@ -314,14 +324,16 @@ class BlockStructure(object): i2_sol = self.sumk_to_solver[ish][i2_sumk] if i1_sol[0] is None or i2_sol[0] is None: if show_warnings: - warn(('Element {},{} of block {} of G is not present '+ - 'in the new structure').format(i1,i2,block)) + if mpi.is_master_node(): + warn(('Element {},{} of block {} of G is not present '+ + 'in the new structure').format(i1,i2,block)) continue if i1_sol[0]!=i2_sol[0]: - if show_warnings: - warn(('Element {},{} of block {} of G is approximated '+ - 'to zero to match the new structure.').format( - i1,i2,block)) + if show_warnings and np.max(np.abs(G[block][i1,i2].data)) > warning_threshold: + if mpi.is_master_node(): + warn(('Element {},{} of block {} of G is approximated '+ + 'to zero to match the new structure. Max abs value: {}').format( + i1,i2,block,np.max(np.abs(G[block][i1,i2].data)))) continue G_new[i1_sol[0]][i1_sol[1],i2_sol[1]] = \ G[block][i1,i2] From 7e82b3eee596ceb915dba77eb9a951f8fe227839 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Tue, 27 Feb 2018 16:31:43 +0100 Subject: [PATCH 22/44] BlockStructure: add deg_shells in str function --- python/block_structure.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/python/block_structure.py b/python/block_structure.py index a3f1b312..5bb5f823 100644 --- a/python/block_structure.py +++ b/python/block_structure.py @@ -451,8 +451,18 @@ class BlockStructure(object): keys = sorted(element[ish].keys(),key=keyfun) for k in keys: s+=' '+str(k)+str(element[ish][k])+'\n' - - s+= "deg_shells "+str( self.deg_shells)+'\n' + s += "deg_shells\n" + for ish in range(len(self.deg_shells)): + s+=' shell '+str(ish)+'\n' + for l in range(len(self.deg_shells[ish])): + s+=' equivalent group '+str(l)+'\n' + if isinstance(self.deg_shells[ish][l],dict): + for key, val in self.deg_shells[ish][l].iteritems(): + s+=' '+key+('*' if val[1] else '')+':\n' + s+=' '+str(val[0]).replace('\n','\n ')+'\n' + else: + for key in self.deg_shells[ish][l]: + s+=' '+key+'\n' return s from pytriqs.archive.hdf_archive_schemes import register_class From 3dbc3601732a5caab0eb7eaa17c9356014a708ba Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Tue, 27 Feb 2018 17:45:25 +0100 Subject: [PATCH 23/44] BlockStructure: update test --- python/block_structure.py | 9 +++++---- test/blockstructure.ref.h5 | Bin 218432 -> 248384 bytes 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python/block_structure.py b/python/block_structure.py index 5bb5f823..2dcd7c81 100644 --- a/python/block_structure.py +++ b/python/block_structure.py @@ -376,10 +376,10 @@ class BlockStructure(object): if not compare(x,y): return False return True - elif isinstance(one,int): - return one==two - elif isinstance(one,str): + elif isinstance(one,(int,bool, str, np.bool_)): return one==two + elif isinstance(one,np.ndarray): + return np.all(one==two) elif isinstance(one,dict): if set(one.keys()) != set(two.keys()): return False @@ -391,7 +391,8 @@ class BlockStructure(object): return False for prop in [ "gf_struct_sumk", "gf_struct_solver", - "solver_to_sumk", "sumk_to_solver", "solver_to_sumk_block"]: + "solver_to_sumk", "sumk_to_solver", "solver_to_sumk_block", + "deg_shells"]: if not compare(getattr(self,prop),getattr(other,prop)): return False return True diff --git a/test/blockstructure.ref.h5 b/test/blockstructure.ref.h5 index b290411c9b9158fdd02a1ae0497281b9a0bf8a9c..c9eb42303698a3aad0d5067b8d916f9d52d8ea7b 100644 GIT binary patch literal 248384 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 h`X1N6xySWy?Q#9q>%}tYS&8Q9^9$SM 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 (solver_block, solver_inner) + # and solver_to_sumk taking (solver_block, solver_inner) --> + # (sumk_block, sumk_index) + for i in range(num_blocs): + for j in range(len(blocs[i])): + block_sumk = sp + inner_sumk = blocs[i][j] + block_solv = '%s_%s' % (sp, i) + inner_solv = j + self.sumk_to_solver[ish][(block_sumk, inner_sumk)] = ( + block_solv, inner_solv) + self.solver_to_sumk[ish][(block_solv, inner_solv)] = ( + block_sumk, inner_sumk) + self.solver_to_sumk_block[ish][block_solv] = block_sumk + + # transform G to the new structure + full_structure = BlockStructure.full_structure( + [{sp:range(self.corr_shells[self.inequiv_to_corr[ish]]['dim']) + for sp in self.spin_block_names[self.corr_shells[self.inequiv_to_corr[ish]]['SO']]} + for ish in range(self.n_inequiv_shells)],None) + G_transformed = [ + self.block_structure.convert_gf(G[ish], + full_structure, ish, beta=G[ish].mesh.beta, show_warnings=threshold) + for ish in range(self.n_inequiv_shells)] + + if analyse_deg_shells: + self.analyse_deg_shells(G_transformed, threshold, include_shells) + return G_transformed + + def analyse_deg_shells(self, G, threshold=1.e-5, include_shells=None): + r""" + Determines the degenerate shells of local Green's functions by analysing + the structure of the corresponding non-interacting Green's function. + The results are stored in the + :class:`SumkDFT.block_structure ` + attribute. + + Parameters + ---------- + G : list of BlockGf of GfImFreq or GfImTime + the non-interacting Green's function for each inequivalent correlated shell + threshold : real, optional + If the difference between matrix elements is below threshold, + they are considered to be equal. + include_shells : list of integers, optional + List of correlated shells to be analysed. + If include_shells is not provided all correlated shells will be analysed. + """ + + # initialize + self.deg_shells = [[] for ish in range(self.n_inequiv_shells)] + + # helper function + def null(A, eps=1e-15): + """ Calculate the null-space of matrix A """ + u, s, vh = numpy.linalg.svd(A) + null_mask = (s <= eps) + null_space = compress(null_mask, vh, axis=0) + return null_space.conjugate().transpose() + + # make a GfImTime from the supplied G + if isinstance(G[0]._first(), GfImFreq): + gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, + indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) + for g_sh in G] + for ish in range(len(gf)): + for name, g in gf[ish]: + g.set_from_inverse_fourier(G[ish][name]) + else: + assert isinstance(G[0]._first(), GfImTime), "G must be a BlockGf of either GfImFreq or GfImTime" + gf = G + + if include_shells is None: + # include all shells + include_shells = range(self.n_inequiv_shells) + + # We consider two blocks equal, if their Green's functions obey + # maybe_conjugate1( v1^dagger G1 v1 ) = maybe_conjugate2( v2^dagger G2 v2 ) + # where maybe_conjugate is a function that conjugates the Green's + # function if the flag 'conjugate' is set and the v are unitary + # matrices + # + # for each pair of blocks, we check whether there is a transformation + # maybe_conjugate( T G1 T^dagger ) = G2 + # where our goal is to find T + # we just try whether there is such a T with and without conjugation + for ish in include_shells: + for block1 in self.gf_struct_solver[ish].iterkeys(): + for block2 in self.gf_struct_solver[ish].iterkeys(): + if block1==block2: continue + + # check if the blocks are already present in the deg_shells + ind1 = -1 + ind2 = -2 + for n, ind in enumerate(self.deg_shells[ish]): + if block1 in ind: + ind1 = n + v1 = ind[block1] + if block2 in ind: + ind2 = n + v2 = ind[block2] + + # if both are already present, go to the next pair of blocks + if ind1 >= 0 and ind2 >= 0: + continue + + gf1 = gf[ish][block1] + gf2 = gf[ish][block2] + + # the two blocks have to have the same shape + if gf1.target_shape != gf2.target_shape: + continue + + # Instead of directly comparing the two blocks, we + # compare its eigenvalues. As G(tau) is Hermitian, + # they are real and the eigenvector matrix is unitary. + # Thus, if the eigenvalues are equal we can transform + # one block to make it equal to the other (at least + # for tau=0). + + e1 = numpy.linalg.eigvalsh(gf1.data[0]) + e2 = numpy.linalg.eigvalsh(gf2.data[0]) + if numpy.any(abs(e1-e2) > threshold): continue + + for conjugate in [False,True]: + if conjugate: + gf2 = gf2.conjugate() + + # we want T gf1 T^dagger = gf2 + # while for a given tau, T could be calculated + # by diagonalizing gf1 and gf2, this does not + # work for all taus simultaneously because of + # numerical imprecisions + + # rather, we rewrite the equation to + # T gf1 = gf2 T + # which is the Sylvester equation. + # For that equation, one can use the Kronecker + # product to get a linear problem, which consists + # of finding the null space of M vec T = 0. + + M = numpy.kron(numpy.eye(*gf1.target_shape),gf2.data[0])-numpy.kron(gf1.data[0].transpose(),numpy.eye(*gf1.target_shape)) + N = null(M, threshold) + + # now we get the intersection of the null spaces + # of all values of tau + for i in range(1,len(gf1.data)): + M = numpy.kron(numpy.eye(*gf1.target_shape),gf2.data[i])-numpy.kron(gf1.data[i].transpose(),numpy.eye(*gf1.target_shape)) + # transform M into current null space + M = numpy.dot(M, N) + N = numpy.dot(N, null(M, threshold)) + if numpy.size(N) == 0: + break + + # no intersection of the null spaces -> no symmetry + if numpy.size(N) == 0: continue + + # reshape N: it then has the indices matrix, matrix, number of basis vectors of the null space + N = N.reshape(gf1.target_shape[0], gf1.target_shape[1], -1).transpose([1, 0, 2]) + + """ + any matrix in the null space can now be constructed as + M = 0 + for i in range(N.shape[-1]): + M += y[i]*N[:,:,i] + with coefficients (complex numbers) y[i]. + + We want to get a set of coefficients y so that M is unitary. + Unitary means M M^dagger = 1. + Thus, + sum y[i] N[:,:,i] y[j].conjugate() N[:,:,j].conjugate().transpose() = eye. + The object N[:,:,i] N[:,:,j] is a four-index object which we call Z. + """ + Z = numpy.einsum('aci,bcj->abij', N, N.conjugate()) + + """ + function chi2 + This function takes a real parameter vector y and reinterprets it as complex. + Then, it calculates the chi2 of + sum y[i] N[:,:,i] y[j].conjugate() N[:,:,j].conjugate().transpose() - eye. + """ + def chi2(y): + # reinterpret y as complex number + y = y.view(numpy.complex_) + ret = 0.0 + for a in range(Z.shape[0]): + for b in range(Z.shape[1]): + ret += numpy.abs(numpy.dot(y, numpy.dot(Z[a, b], y.conjugate())) + - (1.0 if a == b else 0.0))**2 + return ret + + # use the minimization routine from scipy + res = minimize(chi2, numpy.ones(2 * N.shape[-1])) + + # if the minimization fails, there is probably no symmetry + if not res.success: continue + # check if the minimization returned zero within the tolerance + if res.fun > threshold: continue + + # reinterpret the solution as a complex number + y = res.x.view(numpy.complex_) + + # reconstruct the T matrix + T = numpy.zeros(N.shape[:-1], dtype=numpy.complex_) + for i in range(len(y)): + T += N[:, :, i] * y[i] + + # transform gf1 using T + G_transformed = gf1.copy() + G_transformed.from_L_G_R(T, gf1, T.conjugate().transpose()) + + # it does not make sense to check the tails for an + # absolute error because it will usually not hold; + # we could just check the relative error + # (here, we ignore it, reasoning that if the data + # is the same, the tails have to coincide as well) + try: + assert_arrays_are_close(G_transformed.data, gf2.data, threshold) + except (RuntimeError, AssertionError): + # the symmetry does not hold + continue + + # Now that we have found a valid T, we have to + # rewrite it to match the convention that + # C1(v1^dagger G1 v1) = C2(v2^dagger G2 v2), + # where C conjugates if the flag is True + + # For each group of degenerate shells, the list + # SK.deg_shells[ish] contains a dict. The keys + # of the dict are the block names, the values + # are tuples. The first entry of the tuple is + # the transformation matrix v, the second entry + # is the conjugation flag + + # the second block is already present + # set v1 and C1 so that they are compatible with + # C(T gf1 T^dagger) = gf2 + # and with + # C1(v1^dagger G1 v1) = C2(v2^dagger G2 v2) + if (ind1 < 0) and (ind2 >= 0): + if conjugate: + self.deg_shells[ish][ind2][block1] = numpy.dot(T.conjugate().transpose(), v2[0].conjugate()), not v2[1] + else: + self.deg_shells[ish][ind2][block1] = numpy.dot(T.conjugate().transpose(), v2[0]), v2[1] + # the first block is already present + # set v2 and C2 so that they are compatible with + # C(T gf1 T^dagger) = gf2 + # and with + # C1(v1^dagger G1 v1) = C2(v2^dagger G2 v2) + elif (ind1 >= 0) and (ind2 < 0): + if conjugate: + self.deg_shells[ish][ind1][block2] = numpy.dot(T.conjugate(), v1[0].conjugate()), not v1[1] + else: + self.deg_shells[ish][ind1][block2] = numpy.dot(T, v1[0]), v1[1] + # the blocks are not already present + # we arbitrarily choose v1=eye and C1=False and + # set v2 and C2 so that they are compatible with + # C(T gf1 T^dagger) = gf2 + # and with + # C1(v1^dagger G1 v1) = C2(v2^dagger G2 v2) + elif (ind1 < 0) and (ind2 < 0): + d = dict() + d[block1] = numpy.eye(*gf1.target_shape), False + if conjugate: + d[block2] = T.conjugate(), True + else: + d[block2] = T, False + self.deg_shells[ish].append(d) + def density_matrix(self, method='using_gf', beta=40.0): """Calculate density matrices in one of two ways. @@ -1616,3 +1979,38 @@ class SumkDFT(object): def __set_deg_shells(self,value): self.block_structure.deg_shells = value deg_shells = property(__get_deg_shells,__set_deg_shells) + +# a helper function +def conjugate_in_tau(gf_im_freq, in_place=False): + """ Calculate the conjugate in tau of a GfImFreq + + Parameters + ---------- + gf_im_freq : GfImFreq of BlockGf + the Green's function + in_place : whether to modify the gf_im_freq object (True) or return a copy (False) + + Returns + ------- + ret : GfImFreq of BlockGf + the Green's function that has been FT to G(tau), conjugated, and + FT back + """ + if in_place: + ret = gf_im_freq + else: + ret = gf_im_freq.copy() + if isinstance(ret, BlockGf): + for name, gf in ret: + conjugate_in_tau(gf, in_place=True) + else: + """ there is an easier way to do this, namely to make + ret.data[:,:,:] = gf_im_freq.data[::-1,:,:].conjugate() + ret.tail.data[:,:,:] = gf_im_freq.tail.data.conjugate() + but this relies on symmetric Matsubara meshes and is maybe + not safe enough""" + G_tau = GfImTime(beta=gf_im_freq.mesh.beta, + indices=gf_im_freq.indices,n_points=len(gf_im_freq.mesh)+1) + G_tau.set_from_inverse_fourier(gf_im_freq) + ret.set_from_fourier(G_tau.conjugate()) + return ret From 69aa8945867f12675fb88a1570fbf980ef580207 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Tue, 27 Feb 2018 19:55:06 +0100 Subject: [PATCH 27/44] analyze_block_structure_from_gf test --- test/CMakeLists.txt | 4 +- test/SrIrO3_rot.h5 | Bin 0 -> 532472 bytes test/analyze_block_structure_from_gf.py | 179 ++++++++++++++++++++ test/analyze_block_structure_from_gf.ref.h5 | Bin 0 -> 73312 bytes 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/SrIrO3_rot.h5 create mode 100644 test/analyze_block_structure_from_gf.py create mode 100644 test/analyze_block_structure_from_gf.ref.h5 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5ebe0867..02edb21a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,10 +2,10 @@ FILE(GLOB all_h5_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h5) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${all_h5_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # Copy other files -FILE(COPY SrVO3.pmat SrVO3.struct SrVO3.outputs SrVO3.oubwin SrVO3.ctqmcout SrVO3.symqmc SrVO3.sympar SrVO3.parproj hk_convert_hamiltonian.hk LaVO3-Pnma_hr.dat LaVO3-Pnma.inp DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +FILE(COPY SrVO3.pmat SrVO3.struct SrVO3.outputs SrVO3.oubwin SrVO3.ctqmcout SrVO3.symqmc SrVO3.sympar SrVO3.parproj SrIrO3_rot.h5 hk_convert_hamiltonian.hk LaVO3-Pnma_hr.dat LaVO3-Pnma.inp DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # List all tests -set(all_tests wien2k_convert hk_convert w90_convert sumkdft_basic srvo3_Gloc srvo3_transp sigma_from_file blockstructure) +set(all_tests wien2k_convert hk_convert w90_convert sumkdft_basic srvo3_Gloc srvo3_transp sigma_from_file blockstructure analyze_block_structure_from_gf) foreach(t ${all_tests}) add_test(NAME ${t} COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/${t}.py) diff --git a/test/SrIrO3_rot.h5 b/test/SrIrO3_rot.h5 new file mode 100644 index 0000000000000000000000000000000000000000..5ea92a787ef2b3934b838709549181b3460c8d30 GIT binary patch literal 532472 zcmeF42|Sfs_s0)PDiw{QqL~H_Dw-?}N~KbWsE{F#^maYhhiLR3P7O*TeYB6eCOw}26m!hI(q_AH{?|>2Yz_)$v{f5f4 zgWvWI4{2*F>lzr)j(zK@rMvI@6*L{w?t(wluNYH@0d=Y_JM_!^r}|Z-4#?AS8Kq93 zV?&X;KVPq7z+mb=#js=lC3U}!x5E$*)j<~dj(tU%!?f#2+baps^qWJ~s~$CPma9AR z$UtHGp-!?<>trf-M>vYqsQ#>9@r)n)QM*$lw`^U@&|cL$syBtgL)9%!Hb3i_R;ML) z(fsNd$%MM^v!~-YFV(;u>OO6}9NUibckDY_5o*84`GdZ1(fZXTckI7U?P#gpdTql% z8TdUv>QoOIs6=V;Ftz9F+csM}=nmE*-+K;h-}`o)k&*FxR~G6_$i$%7(T&>sd*}9l zMpE~`b>5ojD%bgT)qm6OAL~(Mbcd&k9nCNQ{T_6CFIxM{3%+-F3BT8`OL{2=20!>W z_W$kmzY6Nx`1q?%e{sI6{rlPUuk8KXcz(9`clUqCzkj2Lzw1vA^e6Y*UqJu2`uvr? z{=)P>I`u1i|2Cd~HX$=>f28m{MeqQ?qB+;{kb1)|7`pCbxQ?~%ZbqD zrNLAOJ6?qUJ73XWF9uN0)B4l;(OTN^pZot$+}}5C?zg|$TI?2~UAMzZj&;(K*&?)l zKaWG(r}@W2?Kq9vQXl&$Q>gntx3vDW`92~8WnB9k4GTqT z`-W|j3hf^@E>=)cGE!17R908jR;5rzwL3Dry(i5di9<%}x;o?~ho&H!zyI9+d#e2(XNLc8|Bv7IO}IMzQS4~i@8iGzoL+BIM@L%y zpcX#&p9hBdyrycrW{*OL5c>X$( zG=0=f{_B3Uc}QZ)U-zS#EB-}4Ug|I+Q~!EAT76CZMZdou?{2yuW4lSI-r}Gdr|O)BWF9F1eyF6Zo^|3ca7^>CS$xpv{LrKNs}g`EdSk z-ETk7hrHDL>(4Yon-3q+Ca6E@NShB8`TnE>^)L^$t@}kknmLJCe?1IZ8- zeu_-Jm^A&Kz|VD^R%a}!fB#PdKr1`6&rii@C;nmEQU3-|XyZDL`|E*3sHa(|6A#Ug zpTD1wp!O4?&KI>tYdFa3TctovhB;$XNK-WDFTmDuaeQsYYP#nyZ^Y^?ay$OMTMqsqd z`!J%nf5whn_4f$~Sr2?R$(EAy_pc;Z5CVUnKxv+N9MRj~=SHshX9V7hK5P-M`h@@N zYH}4J@b?ImITRKVz5P9Ar1w83V7z>;ysSzSsc-)rA-VEz5O_3LYb(*)-vCCs{wo6Y zxsziy4!lF^+rOenF8*BtqBC~|621K{Ez>E&(IQ_=&(c_G+THpO}!{t|Rb%%cif3sk0kO@)zO;+@00r0%k$J< z+#4XGAJahe)?d=u>*H{{q^s!Qah24!UZ1J{;h>p)ahN^PTmMLAABbYfE$hK6!_SlY z)(3LcA6&Fvg##85z4eDw_K6sT1FpwbAFqc#;Vf~o&l5-&x>7>)*5}jMX98gOAb;(& z$!k*I`b@_9wxfZEEFTiR_3a$?CGYc%;%sE!3=ru{J`-R2E`iFaGAD`N`fmREn&(r8 z1ctX}ko8sjTHgAqzt=qvL=e68)$H{>zr(T@AKY&-N~G_3PCV|51pHGtjEUa*V&?j$ z&xL9OuY{b@wa?K^w!t1 z)_48YNe;+5KV_Uq-;IEH-j@h$ExVXa^wyU$*0+642$Ze4zmwFrzMaLs-?p$`y8BP-u{>kIokOIrdCY6y5egosc)T+mW=oZ1ga+M zBhlL*fFXyvgg~6I>+1Ug`DA_7E}=^X{h7do3)*T#Z$DEZ`&~uAC}W)3M7vs2-?|Dg z8TSVQ{QR!N9@oyfe5*E`b2N^t%2^0{u%4c z%k~9ief;iZPS3UkSBsPpz0tD*x;OSBF4w!1MzTJB_fn@{YXSRfiQecp{oNk9Z<-Z@ zj~ZDYzuUpnslg0USE4sM&3#XV9So9tKAa`>ttZ&iqs4bpzXc;7WqmyL!f-qIqpIyFQl2fD?xI$c@0|FZyi+<4CD;&J>oHJRUiw;uX zD?;>`J6DkCtyiRiE}WRN!S%|4Rd10lf+a!rIDulb$~dC89!~?^I3P0E*@$WX8&cos zCgVLDXz1-D8bohBn*(~X{&x3*r4yr`lKMtZN$HW|M zzgIwyv6Gm)pTODmw&RK3x}Q6}S~T+6nl(o41F3KHDu8Z|`?$r}GNQL`hEB)kyoN3^ zQ3_%dp<@Ij^ll`uE5Ff{=&c)p)43@r@%%lD?~D+ka||T>ZX%$lKWi`1TQ|WbW+(?1 z&GSoYBI~OXDRd73q4h_J-ns`hvC>YUX{+uayG3MuE+U5RA(>x5bPs{uEk}vox(79}@{NGq0_KnB$@(=!4BbOula?{jTlb(QR@w<%iJ-VT zoE|SiU=RY`L7;(s0?}J{fF?G+6Nq2z8pyy-*5@K}=pF(JYTKKnM^5ga9Ex2oM5YL!iXd*YGYa%lJ}adU(|k0kKR^1oASEpCo#tr;PV(tQQ^^7)VBv^`m<>3-n`sx22RJ(Hs5b zyQd@NGjM)AyOgXS-P3uX7yBie!f%M)=q1}dALlWjLH1QQ$BFd3C&UAKAW*n%4$&Ju zB)XTxs9qzu%0-y0kKaqu(eK?D(_%^V*6*|2djix@to}Ie4XJOvCnNpa6Wc-3pNQW2 zcaD2gba3rMeQ6Z=|37+DPWrPihkS(^h~D~hhDmIM03kpK5CVh%A<*9mEbvmk%#zQL z)8FGH@%0V@ydG~#h~9cfF6hCFI);kzP314i`Ze^B>|PL~k}uOZqPJd<2s&|rgLSv- zES{^RzR^j(dpgWpBhnm+-g-I<^kd(Fani2JO_xZ0qo0)bXr#F3#|TL1-AEw$J`%lkBX4>) z75Ypd;KV1gzAC-zpu6IK_Nj{Kt-D|oJCsaQX2rskEB=pF(lk0!Mcy>$<3VueECPi`vEA41kwC0ghn0zpT)3yI#khc&T6p%~=K zuio^EON6i>1iFL3nS3vzx9$KdhsLSxllj<$ zU2KL7PY8S`ut-g7710|JLw6AfKBxIQ_1-;F-?|Gpo!eoYDYu5`jm|~Tjp6$xG)jN{ zaGBJ%Ze&i+rX(+ni2F?RM$Z!H*4TaSsNeFFO(6BHTdC8pG4qfLF`_s6&3|`C9-=vZ z2lI-j(A{>4J^CbYh{w*J=#4&e-xE<+Zpm4zy7e`wZ#@B@4sE6;d=w*kqr=4aP{_wW zY|fp{%q-GF=80K4Bfxlw)P8>L8e1+(ZPIBEF z!hF0&&T4KRS%0uM%-pi z)`q^$J4xzWA5LMPa-BW<#Y>{MK9#aQ?X0(J8H)w?OR_#!pUz_6aXvTt)ID>ex4x6G zKJMw%w{BWWRZmHM>*IOsEADd(zF1H6)>pFC_x-F>sm*+u(@5%D-%n+qh~SeY!v>7&*83CHPdxM*cV-^DpEs#*{Uo2gJ&b`i zpOcz>iQam9p8AV_QFhO-M79(`e~E|0(YpzFG0m8Hmguc_C#fHK_s+`4b1DBjQs4Sf zPJ44G${MjJiQam1hWeLpNB7i>Q){M(^slH$G`*ETuJ{d3qPO0fo&M+7L~p$%8~xvp z?1r@a=j6FW`hTP(!rnk2)vBL#+-k4 zHMxoq_d5h)l(|Fd+rI@#uKz6p+Vd_? zC3^cURHRcU5Exsb*%ZIAh}5@EU`dAfHGxm}^pWW8*PKX?&LOa6=wWq!yA)F2ItM2i zqNbsc)SPmW=m@1pHGbZzp>DLp0=I z7Z5lxbK}=N@eCqeFf0^%)z5Ndlve~r+=GO#&4N)cQ4|XkO zGCGaG*sOY@HyRAmb~%CJy4%+U`;z+B<)Ddy?*y_wdJw%4Ep!`!a(O;w)+$opx(zs; z8?t|@MD#}I8tBgON1QeaT-x}HPo-z#VI53#%H}y1S26dm-GE(<{w;vOQ&v&G2B_}wH+d;f1gObom$zHd-O=1{wS-yKOEa&+1icL?0!2yi|fBF)AwT?Rw)#=_TO(mLRuYG z6~FIMC{o)+MZaC$_R|mbG=)vOqko4j+ELQd3js0FRTAG~?YNu1>8Ru9j^_WWmqM9O zJxZ^L@!nH)`sjt!chBGi3FfsW&j)P9l6sT+UN_)w3l ztN&QHe(oMjJzzquJ2bmL*P)-U>uvj;e}4r3*8S1>b|e3mU78*kC>?hML&xJ6<>%+R zpZEWMy^o{%CH6z=|G3@{pu|yo$?E*I{)(yniaCE6_W$kFQIDAD|Mhq;sr_F5qTl~B z(8~_|>Nz#lxPt>rFY}wY(>(-!o)6imW*raycz@95Ia*!+@$UWmzS8DHF{2JU>QsCG zZa(bF=hXMVRZo9@P8FfvUw@wveP7Y}^C9gO?8i#?^Sq-GJkd-;{70<{GJ`Rw%{($6>B-?tq+lQ*EqJ1>P&OQykos zk2kU(%%AC(0+A~Rm2Nbvgp~t#tywxhABR`QE`1-A0hh)Wo}7_+AHGn69ei$u!=VeK zsB#Y3lJFSgzQxJ7>EU za3>nZ7zS%$lD3$Ptd<7ccoZOYx7H7q8sxYh04LPCutK-|lndl8Nwx9wGe<9b0Y{A{ zBU~8RmdromFosRbR#}~|hrTr;Y8v9^c;)kB*3j}8C^mb1e(>=NU{x)?aEFX2s7Fju z#vpazDLg;nq<|$*{Ey^LzG{yOca1Crs!Z|4^v!24Z8gD@kau*B_Q_K5YNxWILe?y$UQ z{|31*C0wQt@&U8u3+^?Mv13t`Wn@efPNgRGo{8=9L_ zA>ek)_AQetV3gpjjoZE)L+NVyDi-V7XY09zKzANE@ijC;lu z+cds#hipspysY&~U>nNmx%8?hW-Jvs5vgGc@z(34b!SL{$QUlZCC}6`QN(tQlh9f0 z>Z%@`_$pBH;WqGFzDaz>^u0*2VA+s!!X3iKCbXpb#Gugl)+fR{Gaz=Ax~IHuHagiP zGFRIqV6cGZ$TF8qC>b(Et7=dIBz=A~j8`fhSr;Vc8w9lXODkFbW=tw1j{3U9@V+Fh z%)UEa*vSJdzaI1p3^;{V^HK^dOg->GmCL~jqd?5GFcJ-|K86yXx%rE|zWFbIGo2fY*ao{B5fHB0EwVT|T6&({tpqBLfo zQI!+A@0&e!_CP~)voXJ5`?3=EMe)=tWfZ^+jaO#pOm5<9>um3}E|rk9(lxzoYbe}K zS75K38H|&IPRr&O$b-?weVX;k!jSlRebiz@d)W0XLhH#Z2dofQZ@6~R0Q27#T(??d z1E+3kJy=Qc2H$4_Bc`m@gqd9NjCw8(c%RRTJ@kl2m+LF*H5;4q@>=vwH(Qr``8tZ2 z8Wl2n2170LJ;MNt7^sVFxcYqKMXcE4MG4@|fXOKz*Jr&gz^CVZ_@<30fOr!LkD1&l zc*A$=`Qn*HP-iQ9O65%sX6!tDWvNp>aNksa!80-q9N!%=X>Gd-5{ti>rrEcTH|lno zJYyDeNHu6wj*dr;O?)4#A5>ykeOc(UWzo<&-g;NU@_ckKjFXt>cN1I-QWlJe^}^zj z_YGOsc%xd*qt6j;5va}7TGO)31MfWHU-dj&03&ueNE@zmz{>OoE7v|f2&uEx47lFK zV(Gp)XNKKB1q(7ul!Q#e@S}fu^Wa2#nDm8j-{iH9SP?0=T|6KRPL}#Cm0l198dK*7 zR$3+Exq;Ca_7+(}dARkiFD=@*J1$ZB!Mc68IMC)pXo3nP4L+~KKEoK!E>gTH8l;SO z8spg5t6PNKo1X&g{A3CK#Eb&GPuIJKURHJYesH<6v@%@+4-P5k48p z&2(kBJnVRyJz+~}AyU}oyX)CUci$9?%C2AztR-dbOQ_b2)d5|uB-=f}Lb zvKXYf>GJEK@m_Iw`B3X4jS)4d_?nrbcq9+S-r?2bE9GI1xV+=BU2agV zuP-#vIRow<8o7OsstT$Xosw+JK8YJL9&j?g3&6=|-U}KIHimKaZ13{|{jqGs)Ye0i zHlX4M`P&r++?TY{{r4@0$gjkv&ZJNR&R+~^nE?eR`?D_+Yxx-mjnL zxP!zB8PQ;0In+HYxKeShH=I3vE9m@TcWjFA7v_jn#A(Mvj18++07rw()341LIPTFZ zDXqolA@BLnami{YV06hVX|D-E$eVCQVD#xEv~pgt^lD=&i0(GEd%Ptcu30nB8g7@; z<LzD+Qde@UxyP;Uz=WYYZv4c zh7>>W4uNS;jEoP>KMvPc-wGUcHWWsk+Ig;8#s=2Jmw$Qp)E;t|`cC9oYy)iZr})lA znc|yZLF>HuH2k)EVMDm*D1wd zIxjBr<3ZlA4a*p~p7zrxqgHTnGQy$Fb=1?gQ^N zjSIMjdE|x*ZweuIVFtt5tP&6$&N`~$**$DnCu4VG$_8BVmBIUn+Ag>lrEUK@$N)d7 zIrwnKZb8BDZSb5`AKl)!nXuOG#r>N3{zh;d=BySPF{@Ay9xU_nuNmNmcMcpkd%n{I z?bLNF>W2itY(E9(V~V!mE&S<4qQ4q2TnHRuyW0}Ywu`=3;nc%DcXgDD*O)=`fqg?J z1PfzUTA}5Xhw3P3e+U51@q}AJZtMnZ4@Z+WL zr<_SemL>FrFtanVPpv+?b@LUtv6VCTz^xcu_jblc#?4n@ zhVCcl1*x%+7I8f?NuUbjD$*1tt7O7O#V1v7M_fb7`*+17Y>ME%g(vf2B~y677Mv2J z6$uLV1FPdS5@7&y%knu>sjR639^p)h%zW+)3p`S6Hr1Cw^l8Cs%|}z9Bqe5-+uS3#HCR)tE_gSb zz5Hmem0cWUyY0Nrpmi3m6e3SOXBfm(9$w}c7yxfJYiCS2FO9*>ALO@wl?MF=g>9of zjBv<%?Sezk&G4BY1bj>}2Q`6PQj5Y;O?b6=Hu87gT|^97291iQFhGd zCi^=Qs5Q{<%24mUc;rUKgYDcqaKEtC$Mqq*&}+b2-WYp55ZM~p>R+h_1{3QQ>Ien4njkV(QrP~ zgRo~{{)%Y^KFIYY(Y?6Y6HmY3DxbM!3#=539kT3`C$>Gxpf16MR3 zebBIKf8G*nYAcY{g-vr?$7~;F+~xIa$KbiQzo-VIk5P`UNZVO-Z)P%2x045x6+@~V zqj!VH`Q~xMUZ#R`MqTK|))bgKyY}5B^BfR5uf9QHQ7XI%cm*XJb1?Gew)c^;NqD|$ z&3fT+g?Kt#&~WC-WX#E$tNHmWzz(+yJJvD=!RCos)i0kOgJVwzC!bfcgJj;c1%Am% zAjG%#rq+c-U~s&W7kSYVuC4G|cY1L!+?X3yJ2Ny9HkCPOXXoZ&yvp9#5d!Y0H==Rv z#+>7*^Y~fa>-ro}ucu5HJ)jCp1`Xuk&76g2LLRPu8SD%flnkS}%8KB&`x0Yb_glDZ zo28LLRtA_pnRAy{wGtaGO6-{vG%k z3%DQ5nS5{FJ~+$Xa!c}<6|6Rz851624SAJjB4V4wU|Y=^UJ;B@Y<(+ZB_xr@02teNlN+p;(7-Svxc zn2qfqGpDPtZF)j{?4fLk8OB#FEGUCZmXEe!VA%#!mfe~payJ65&8wK~!|nmj&1+Q5 zui9XZSA`>j9(ZxxaueKf6e(Go&s@D}3x*#zSvcf)A+PF?DtwFO5oz|7rz- z%#v49Qg_2!?GqVX211Z()qL-Yy$qb2VYO>Ol?e_Pb-%T9umnzv*sk$sR2zp-Z#(h2h1= zmcHe>@$lg42FCjMYiO`Xs!e=sBzQipG~RvmENm9pwZqJ`2G>29y3V924TC2|)tc?Q z0=wOr1*Z)2h0XOAr-py6X#YHN_m;efk>Ky4Hr-OZ6lZ#wZoXfZ3w!F)j0?CcVM*(Y zrp!|fAaQnf*6rPnxMB6E3H##Xky15PU3$ZDV6M&?{-PukM?Y`NOIdaaiUpm#<)3O{ z&BV=+nCJ?v(fliJa@69C5xK^y(wXq_b?}Y}4aXrh&Ca_*IvDd0H-%2n$bg)hja3Q! z_SkAPz*9+z?PS>ACm!DCM)%hiXt zgD2bNCFVlzAZzbve{A!1yimVfcH{_qaC9Ad!z@r9?|)r+LgS_)&qM7oW%QuBQ}gR$%PUlxw1xPeR%Jr-xMMujD?w5tJNYifc=a3 zu#*w7*fOgTO5WN-;74AorSU#kWH7$|Txh$FrL^y@xP2Sfa}VDo<(7;(2eh5?_zK{e zA!XB0`Ftpz`=xfXK_!kpJ8UZsF0vU!Nb^nu|%doSa`PUBq0OfLrV> zyU`}d+Gk*cJ|xxi%SrLb;9}`#L$--;##8rBoXS$1>LD6VwgHDB@!tM{HiL{H z-J<;~k|uKqQFR;6a!wbxMb0kY!H|OYG%7D|KkkD<=dLPIiAJwpa>xG!K z#WrZYv2gxsabp-2w%?wI-w{Tye!hEW;XcR`F80$m(nl|dD0z~qfl~&v-+k0#jjjws zqMR;w{qvX9jPW_TF7CiKXuU)8Lupj=u#nK8q(Sh8Df7mtFM;)QcPdPBu4;c?_gs28 zB^_#CzZ-h&K^aQf>YHmkj>iRYBC);s z=%)_poID1}ZaK*IkYl=wSt&S2?H{teCIq9NU5b;@4}t8fYb)c0&qHY3BDdzCXmnZ< zaw~|}3epculhO>6#*eC^`K~NVpgjcxFFsI)cy(r-)*L6~x~e)s+a?$?r-UTF`K$&y z(200COxn|mttP|Q3FNbv%P%P#i5$v4|GxqIV zGCtY|CmX(6I+EJ}V}qis3x^uvupwg_G#ORebD%Zig zZU^;Bt~;Raf{D@sL4GJJ*y^8uh6j>FpGwK-hNI^wBk@TQ(p~=kI6AF%q(jIyXwBz! zC_8NhoUS!t!e!BzRrk!{dWjDdj9JjK{eC9y9axv|5|s(3Esk!}UXumIAHIIdd~^Y= zYt3t)6{I2GSjxq>dkVmk;YiV-O=%E!*!yrRdLod9n9R99^ z(+zoIF19sn_k?xHhJ&rP1fk`Zi-|{{&4I=e&(*CfQX&4Rc5A`YcyMoIvA%Yg2fuvQ zTs}m{0;~@WRO1rOLcdFyxl_mF;@KVgTiEI?k$KsrP+?;`baHt@$=p?eZT9E$1cM7P zvOqd@@8Al&KB+RKNiq**=4B^b&aDSO87Ir^LzS@V@^bAfvd2MjR$RKseq)?Cmwjnk zj0N1>J20TxRR)9WHnW+h*uneyJEl`}596VIX3P!8G;xOQ^y{87;xJ!rPuv7EZ!r)X_Ib zar@0x$#d4`!=Tkg3tM(op})gGhlacgcyfkIVeGS;=$V?Qa>mOACt5QP;}$yu5|`4C zPUBdM+1rY}X6J2#HHBM*rakq93Z~sD@0S{(nDrq6HG>VnGwj%~EkzVec(>53IMEwz zHG|X!>w94R>|5ze%k9wqfYz;gKKU-!m#bp}$H6&u_-N@lyERVjery&Hah8jOnytQ% zhjTlk9%JRyrw6jp^|%e+P)a#`KER<9ZIzCt?ceV?Ra67FV&FO>Tx z){V*D8-}|!@{JX*setR6`zAHbYrun+H;;x(7U8Xh1I8t?mcd2t)-AJVX5t=xp5nb# z86aq|yK!bje*5$2(m=QN=g#dC;rDmU$$)bQ8KhP9YOrQj&;=js9LRpoDLX3H6Qno~ zxQd6L1u17Sj+%8Duvz8cyXHiFs1wRG_ndtSjdPdX7$g)7r;^5Qc|XexzTT3v7|rDm z))_h@G`HA-T)-*EZP~K0OiIG-b5kI0d1tueja3BBnzVA-1m$2DHzc8^tvL}|<)&mE zKnGwuls9@s?Lbj6la=K+S<>aU8vM#>jJpGO+0J*J}oR%P?rZ zx3f^CEF|uDv~F>>B}7_GIpDzRiY}kV6co6c!174biH)sxIBI1A<>GpKv|P)~R;s=b zFKNB>`Lxg-UM@JG5IuM&1U+6;7(LJzj3dsba#kOLwTl#6{U<47e$4)|nd4`+zsC#S zn)D$KCg&*^pE-~L9~crF;DbL#9&`J8m(LSFsPoPCR?C6ay3gbGwz%UK|1WmeHaNnW zi3gTfJ))Z%M}^ADDasZWf}; zykd#jnklGTGod-%xDqb}t(>~is~jG!Ju1upB^Y*$<}lzbDg~ZFA%TXUOHuvwO&!*? z?SCJ^)-1RPE`W=&{*Z|}H^C?T&Gd6Kqe0`w*i|;?oRDMr4Dl1$k(lPbt5Io?2TGjS ze8+pIFh;V(=D26uBk$(x8r(xov0#SBOt-l6xLy3EAL}h|eEU@?-!35xtMg7i-!j=2 zdAv^yJIt(tch&@#f7%p^((x}ftjt^BKy@O_;AxX@PO=2X$j2)R6t#gr5hVpn z_aOsVU7B-Q6(6YzM%Rxp2DLNAB7*M9U|C={t;vEPI6j^en{T!gxHJ!LyOd2p zCGb<0(Gm-gj~(H~Vch=wWoBS?h{*t1mYY1&j*>=`?Hfua2jxIR-Ro)lM00^<%xkYT zif54BPC}to-4ACh%oAQOkc!e1Y8Zw-vICU|3!gK7G{I`h{N}t}iCzADZ?to+>F1gl zXb~3FUsMo+se7lc|7b1%Ix^FhCP&KS>+KhVmU7DB%B7CAPngwFG+>s~RK*YwyEQh& zE9*G6Jd=zU_!J5uHTpHY^DOb>4uyHGNk?I2PRzubSQCsfVu~1ZBo^|kS6y*Ae;zcC zFcn$OO~XB(t`GP4qy`C0MXPRaj=-a@cx&!e<-n#L`Udfd0pZzT=rx+`_8Kn2iPxOcvr(0*GA2| z8KQ9*^q)vn4e_nQ+W{JHwwoff1}1+=(k?``W5Gsa=?S?4qYC$M^P&gBo={*(8L`pI3>EXD@8#?nR>U6oj)K4$eGHq6b%r!QjnA=iu{=3_5*R^)x zK1MFCP#bs14_}ul7!v^siqfJ1@#P?s;%}mK^a5!6pAZ(}y9(tpeB(KXhM)(Z=xuG+ zDt!5M{sG_N(Ws#HHDzkeHB3f5U-`CT%*+tx+dnD>R4zrytSR!r`68Bng>V8nH*S3U ziZu-#U(bAzu6PH=a7JtqTbPE23)z_Gv1GvKvAOm8WUj*YLqi{&n;nO7Hcx7KGxcCw z9>4I+zM#HsYVTus3 zm!;z5Q+ce_XWf^SEe%ue)jt(-(ucJwLJ^8yD(LmbCFF9O5$uVwU)Uy^98;9#4`UBEYGkeohmyG$Xu5jv zg1Bmz>+AV;*1ZigeId~+^6j-F(b$~uWo)pQ6}CQl^jwEi8V%m(>jt+b;oT`SsvC!9 zK;y@ve7hh-MX(m+3rd6N6;(VILvvy8i5qIU>=$rDs_j&c^db3^?F=0Ut|TvurfWM~Skx><{9O;J|_F%lDk$kE1rOY)u}NgIjM~pDI{X zg>vTExy$ccL0a?I#hd+YVNr#B((x0eXt3&`%KVEr(f7UPG-bYQe84)3S$t|GZa*9= zx+&TaEcaHMTG}1L!wWXNi5%jLIh#hDQ=Q}jmmVAqa4?g^nYLHG;!`!?zL5gYiQDEl zde*L4A2-`V_VNQ~2dx&wS1(gWUA?9ap4T)TcC}w0bcmDZd#J7_d$ zYLXeSZMzmNn`nlur-vL4GChWy9Y^mM`f?j?#m$vx$uCBaWQTReepm70(rsmG#aUn! z7<^`&&^9<{uQD{~p(sApkZ4FrYq#xNy&mTW{}ErUU}?zmp^}DVSN3 zf^JgspZ9*K0JpUQEY}8k!<5G@(&dV!7+j(z&l_Wh0UFZ!8*R>k#+D%?%1o~SpF!M_ zL5VlO%|UH#h!}jQ~3_cNBPeXpQ05 zbO@eSy7gTUKYTsmtMSIs7Ur#(?ydgX7e6N^$^?bj;pho3K1g4V0ilezC-B=@ZpQSbQ>av|^ zVSfAA`SOL(vd1?kqd*o0ynMS`M}7m2UzNG`6ssdzygYS*J4hS0d=Z^dukQ}}4+dl^ z%{0Q|cM6&jy6f?R*jrQf)$YK--GFTy zSYHb{RDpa#zHGj7E;cbQ8zfj-jG>XbYdGJ;!-=o2Ue-=4fV(McIF@Y9gE1>w%bMTk zLb{gPhXu+7$Rd2O=q+nDwzSx?MXD8|xqtk858(oQ@_6YBo6VKDaHR9X#hcS0cE@}3 zL3s#TaqroL-nro9jW@=`#3$pW*Rc#4cdM{b)FLYTSW*;=-|?*fz4LwSNyI$sKvc9X1|tx-_TK0K6|6N7~H^ z2X7zcAr6Aaa0_4CiGcR+iM$@qn6TU>5^b(mr@hWf!u){_{uX*cSQc+PS?|6lzDvEF zTfAEt1aB9=NxHHhA`4w_nIx#e*Lmz&>vvkgr>BEjo2Tvsr!pzV=(r_NJ!g!nCyyew zF)HRpr5NLr+PPk18|Q(8V5Go+v3rr7k$<16{!}RsdCqW^!R5&3T|3dT_0z-?N&5I2i+I!q`M?cBtHW6ntucPW z%LMjIQSi#>*5ik&mblo)@2TU}0?>{rOmN&0%NuY>XCV!xF5}vh~duSW? zek?rK!0*NDgp2vt^UJC0S;01}s!0*j_ zbIF%5nCOyire0~X8Cwqve!bJc>d3_Yr6n4Uq?X)?kqv>1 z5|3Q>4>N%yCq!dXI8LI|*kM+S%^iU`MEuSo)>yQk9eT9U?l?Z!RIJg!7>#=)#K(Lz z41l4nnqp^F?t)RtDy4x5SAi|)cw5Z95=f+c9xT`XcYhM&gzAfG{BYH)uU8^mt5IoT z5{KYgAG{})vK=NhqU?JHyRQxwFzwm#^(RKILdM|^OIgNR0@o7$kTvO^xVcCsbNbsP zd~dzLTgA`~ogLnCJd$vNvZM*VHccitqhR3mshr8}^VUZpHr{Z!bbpVnZb>jK)?`0d z^HvR`MlamI<617}wM88sr4j`n?X_o|3P`|VEJbGA*=KN1(>aGr#qm(KVWhD3$1sd6 zs`Som-hIlk+6#qNtzqMrxU&eJXS7Dz#Gw${A{ebcqF6&-dwx^Zwy*e8^&crYW?R0qfP4Y zq*6ZL`FYtmKZ@65T}3j;EiOI4pK}Cxi#{DKJQ<41KHk2Zk{O9rZEcO#)j8;Mu9Pt) zDGYU_D)&EKnhxpL#b(GKbb}?Ti{1{LQ-qV<#w)xv3C35R%ltks&&7#@f)6-_Wk3n% z=-G;I!yrv|cg>Ape^4A2lCB5NFz8`pZA|WVkhZ^ecc!r>)V^6=4Ld_HiIFLQRn)9K zPese?OwQsyQ8U)ItuAmPuKC`}v4`O0n4q!E#^wn^}cw6~deYk21 z6qyvqSVnj7QQCU7&NmwGw#8mr_^AEw%1us*N>yIKEfb@~Ru?)Ur}p%<50+Zu{Cyt= zzYCa*kv1Wls=1FKU+@C|O$r9Eb7lG6dxzuUZOmaGhS_0wH%5?Do@=F~m6M90XT7o+8Z(LHnDrW9jU7`Rr&fNNVY4B`2_O-9TO zZcDtH9(=L={h)~H+Ww?)d{n0%9)BVg@87&S?DRWt+%a4Ht#D%!JbLsx?>9jw#>AKTQQt>p74g_v1>CAzi(_ux3 zwKH3U6Z&V$tk!vU4D00A#97@}h2*UZ$_`Ic1<6(Xr}-4LVa0;k>XT>aqr$p$uAFg4 zQ1-2@#EE&%xNSkDfQ_&e#9Q8fm2$cOxE2iGzfAZxrVqC)7~l~F_XDHSjPN zTU0n0WNOQ9)bj)HOgWV`C4RU}dvPFhfFJJP5Muj$fhP<%JNYzN!V4sXc1Q#b41^_{ z+$|q|IF4@z z*g=}=nK3G34Dni;$8sh~1F)aIe#K(*7(5#9%lbez1BYJ|6)4v=z-70j%VwAw{8C^0 z)*Du6w%>n8i}z}X->?Oi1)(pM2JxZce#w_jN3Fq8lYM)c%0ZOWIu@-PAAu|=#%JUb zj>7{bKTj{Z02i8kRe38*Aj>cCXv(q%*m33hgxB_gn6nuQxdjsN&Qy!r&{BbqI9fm4 zy;uW9`_!Jb*(G6=xq>GjS2oO!D2Tq@l8VE!h1U}l#7w0};Y7D46{dgHjuvlm} ztJq4Pgj4_j2s`h8D*rc*YZ)m~DO3^?Ny8?cOOjAzXH+sGtL&Yv=rx$Nf0xdcW`M{kop7*S#d33N%f(IBx|6!RL)> z^^nFikgLl4^QOWL_Ihj8(;C@ec9bW1biO05wCxL^3k^WOiR$}a^j5&JBSAQIFBnoq z+#P<-#o})kg;&Db?&!K9U7*r!2~DyUnMo4GShm0Lv$%R5a`E5#{&PDQJwKl;yrts; zaHds<`g|Dtia7)<_O__SBl)>6Aq*-=1MuNCXQ*9W`qjD|fn+A)oC;FD@b1wqRy8v_ zH1r*v@k>$r&;D&lPTWlFPY5(Ja|h`3=3|Ykq|WzVJLs<9^EhCb0^eN1#dfuYkT_od zMDoAUI60?UEIZW7za0lfyTYGOIg@ex*sQi@dj$q{ z7%!_gy#-Y#tuJvWhVcXA6_a+_VsN6d3?wuTY_i8(mUp+j?>ppX#}4k=^NQ30~ zQGd=oB>kTuD$nbv5uVPvj^y8yA(W}o)vJUB<--P#uDtdm?e`Mi2Hz~OLqe_d+V5n@ znLC+bVqgP_%3eGB&zWQB#pAbBa(z*XW_i)AE&*tTl!isVhG2-GU=5$j9SCDqi5U3l zi@SCmxUoMe67NdXFUs*HWBxzK0{w{BkZb>FvRpG8o3j3f__`FLr&#Wx?oZh$b9M3M z$@p;SJ6qkUESdm)sjLEDov)y()&B9z=PhCC+{Tw}{}jAe^u#1BfOLPR}{mSX$ABrjVtrx=Ci?HKe%zh7%F#K(wNd0_+eci&ZBdjD>Y$LB4Y16rd<%RTY}>ftV?(54)W+;qzScV7pT= zIzFDhW)@NepYH#jXHy7 zcctLh6q9)h;cT#~VF{}IoeG?cadPp5Lfli-oJL*i0Ts(E%%gJ2*!(=}5>-kUrW@qy zthbNAgANv^FQy;B>&um*P_{{&8O*!4=hZNbCoGz2(f5N$db}MuYddacS@uUq`JltO ztYPh6A&~ZD>3ZbUQ=AOBKKwb{3EiTKcPx!>z=Whu7VEJW!19q}yX8?HyrDmW1M$V+ zxN>ZjA~6|#yZS@}Ol%?ez=7uRrV`S6xv(|jU5HyEi{~*s4d>X8*bdZ|K~-Y>$Un~} zpo%mMtus$Sm&+kG>GyMHZtjN2B9li$>BTrkIt-RnJ4FOC1RzHUZZWu;dI;fl>Wo^bn2@Tj1R-PP+0 zid&0`vTqV0ulxE#Z^|Hi!xP(M^34(q^EH#6j=aZDIXw%H6yJmJ)5`Pz>~bJ|{zvWC zd6F(V0&ivW^1-7h@9@V%ZlHT^#0&zO!Rb_J)b~^uoTPcPocp2~wEE&T>3PfG+n9YF z8+jiJwzG!Q{TalHJ_WAS(LQXG{(NltR9=5nqND;DG1VT$$oipCBb|%*AW{rJydzp!+zo2yeBd z7-?*FVCkNy82|ZpxF$O7lw2`@{B7QQMVES$cYY9nvvxSWWl!}g`YX_<|vtM;WsiqKM3y}I#ulk zcH$gL&e1hUsb9(9EgMYY7qzAS$5 z3G7X@5}r`X#oVzr{gI_;XrbLqJwcTUPSVe>CB}H+d`Y&{o|-ryPAaDEt*b}McW*3% zCrSO# zwZTu<)(b(nCemH|h$X6{jPk8N!BaH8t^CUcDqNF>Cu1fB^1 z<@7gi&zQPln5>P!%fI4yuHnvNvv4(JNOHX8z1s$2%xz*6w+2w(gg4vZ1!*1A6!dV% zyTYPpkB;l5G)z0``191y2oR^qcmHmfg-6K_RhuoR;9~UJypZ}cyhB}dN?*tc=IZwq z4nB#+IYHNs!RkohF#AhRF3e~43V~h8<(me^j>zbG zjK0#v1)2FYfBy`84&Fi6e+ioFVD{ef@B8EIQM)1TpUT}5I8ox5y~bGmpY>HHWPCnI z_Zigf*soFdxZz?bMd9tnP&`*=`1#x)17MMw@U#}sLX9`&LUA`rz%Er@spD}5cAYI1 zH)Rfik4sF)7hKCQ{aO%1BxxQ)^t&X*#ygEizQraSTuT7X-gz50ir47yXTeI2r4c^c z-Vk`*+5~p4LYgH%#;|Aeneu(eM>3;Y12?M%RG^$@JA_%#eYO6^UiJzokiJXKJkbDu zRS#11x((oqqIG#wks=uUzG}(cGy*Ht!`h;ogUG4B8ek;Vi89UeGI2SBaQjfRLPTjj z;CNaCnN2)K(TP0r6fH#t>8jdN%2G6K+awQf4#R$7E{U_I>Bw4w;Vdg@SROLG^=179 z_N4{8l=sS@Votn9oTC9gIQAW*l3#(Uia`6mOSW+IP4+^~i!`vauvD94*Mt6jR4f4= zR`4cr`=nB*0}9a_dAwosz^DxiwPboZK>E*2T`tc+D6ZG{nzjMF zW2tDmS0RCBJrrg%Du#PIlSsbgq`b~=QP?sf#mi?Li0YEkJ&(Q^!{svWZn1u87_9r3 zU`y$aw?;=r4bT(Gn8N#%B{)#Yi*+hRCKh8&7T!F_3BlPzwSp&(^R@se|MUgnGkl60j%bvIpr*^cTUvqdNzU3Fj?H+hO0 zbw$ec#g>rD;5ZfI6Am%@0)4X;f%sqf0*74Bh?&+zpyl!LmhH%R(5%bI>XGz87v}8I z2om>z2UJmdJq>TGtS9>C7sE9*zWI*108l&U;I6n8gB*$v#j3_Cp=RnV2SGL%J6r7~ zE>KQ^mTO+i=?0QsXKXB%oJ+(H4?i4@t!;*t6VBHX-!?(qn+lQcf>9I-bamQXe2s_Q zmN*g_h zatZAxe4Y>CrsH4$Ye*433@$CY<{y5!r)Zr%9f@@k zmxV;0C_>`wPWW4EMNW_RjgAjNnu);m6F-gN*7IBQeKTR8 z*-~@+?7JAKOiSGpaXTMw>9;8{lKOw;zYH~D zY_YvVRmapL2n%+;&SyrJ!jBsn{I?PUKs!B>eMC1I;)9PmnW)91X8HKT?^({UP0=tH z%J~>$ohPEr&Ktv-+YM_+IYMA~7f)?Jmm7BN`sSLiA&+#m)tfmkHjo;_-(=Y4iS0jk zjoe%b{?Gb4;$TWE!uK4*B?lkL?J34+K99QnR|0@NX{JWJ2-*YKMM1AGF^2 z(yu<2fn@y_HyL8HVUfE)PHH?2zMp$dEjf{eQuQDbLn(`i7WXu`=Ukxrc$Z|BPbxat zh&~;=Xn~xk&(&Y4jfDGad-#q<%E9Hv^JXhYieR1)+57zfiJvrdx3>^Zg-0t1UfZPo z@#AU3i4fm8+-3Rdes4lPhI;*sx7pK$A9=<%-<%wTy#hV*X}gKYC@5FPM>Ye&>>~;X zf;-XAZ7woRR1qa_KK%St)e~j*=&Wu9g+O;wk;0qLUML_@D=AwO3i}1lS%L-u0|!XpcgCEsi4u~hqoCKUxnX~OCss?+QthXQ&LJmv2}1{ygLKGB|ME`5G@8p zS}#$T-&uHn_a@7aj%+yGx?Z08J_YViSGX<|Wg#Qt_Tqz!$)vO|C~ljhOdx*M3w zr@f*b&qA34)=_ILUVDQ|0utnd1 z9J%HNH&RQ`Kw~8ghjwVwaunk$jsPMI05s9Pxa20!p6Gfu*MCx}wWgz_9*J zcFsEhj=L{~oI8?;KV2w4|A+|z(?yMqw1o^53kq$DFN_0qA!?&(AvZYli)RmqdJt)! z3Ga+rl!S}a$E=3NoFK(eQTO(oIUFS$Jmj_87HIqj488BTKzhFb`|Yn581`LHIkEW# zY*jrm_($?rS$@8Lcv3eAh8K2jzTBySrDe}~r;KDA{7L8A@i7Gd$~KU5p7w?B^p9L@ zwF01NJ=snqGz5n__$tkQd7v*p{)rce$DH?FKfopyj?K(>zxN^ix(%~eZXB!xouHRD zP9-EmK>vc?u}80=e2{UA-@y{Ca&9;I9d|`CZc_?HhsO}(Acl5W z5;ADeMlUHZkOHrek2)uiZ^#XcXj<18 zM3TXF`k&pMsmHKvi5F{GYJqZp$V+9$K)9i)>>qrt8c#>_F;Qn^qEC7Bj^B7W@E27~ zz4;oA-o@@S?WFIK$;6`fR3y~I$)AaB%z%#3bIXT3-EeYumu4q_6pC0{zOrHsMV3BC zm#b{8=tj#wd;CZgt}>LLVfYdY1;GN&oh!7!Sg+ zK$%~!j+1hpPV8wE%&P}l)?|vpQwgvlm~i>EM;b^zVAIL1^+fZ1VwXz%BA~6B-_Dq! z1j1fjof6?lhM!}@`wos*1G~+qsa~yzV7w|$G4Le_WmLul=5Fi5xXVhfZ<01tC;Mi+ zXm-Ym!i}6#H**YsAfX*nqzrlUd=zfXLC9nKfnDwC2k`Sa^qo?)h{Utz#lO7Q2`%~q zZxqVCf%jc))o)c&zjNfqcY`w#@cJ-o>sQVctdMvxOmxXYFN+ANGLCQv%VxiF?pY%0 zoaPK!J{gH_IZZFz9YXQGTJ7l!rFLjN)StLxQw|S<7gIR+TYw?zh*PF%7S<1eS6HJP z96j|z^a!~PK505VwtUQtq@P@AW&P=hKW?dnyX%(&)pVK3rf&t_4;9dD<0El$ZJimQ zWcQ!-)ln=N?>6EGzF}0+6(@3GVqHt#`=vUvW}3z^I%VOp10qkX^FrZNCJmRHb~N;5 zyIUz%XOcL3FHhTk(p-G>QXrwI6Y6>8c0J{Jk1P`6%*nMGc;`XX9inzQ#1991sy$NrDZ&uDHF0>xo75iu& zU+IRB)vsOQH9aU6%wsRfSqjBZziI8&EyZ6R@}+vS>Db0S_J_8u7-&OHD)&hTqO%)M z--Y+i=*sFmyxTGvN;dVE3rDh1V504g=+{I%a^gWzf>9)@yxZXI1(L3RomFpf(-OLc zm%i)?aYD~3y;0A&WOR%QO1U#+jh7!5M(KR{& zaN94lZz80ekKL9}n;yHshDMLPQ%5XZJ~DoRAj}Y$vQh z7APhN+TLV$15=Hpsdi}+mvnRD=YEA8D7Mwg_csj%hJU{M2VzNmO?d0bHHsn(YbYt& zKBxjsSoCw|c{+w_F?VfvM4){mk>m2x15|K`I0ti)*(+fsvxThU=L*+~dz5 zreZgTB00h(;Q>F0f7kRj>{bwr-za!;SJwt;2h2?{Sufaw$Z?tf z*??X-dQ8cUWDQhdEuS;XJefDX(L@+Q$Dl$VuBlAA?tEN%$iW{&nEQ%oZmkPo_aN508ZMP4UbRDlVx%vQ6+53Ua znl;Q7MhE^>P$uy{u1be#459tDZ-^j497O`3`rNzz41_aU`@~Nxz{ANrX^k&=_&mnO z?G;H!7tN#G$KhrI&Q=fKacx>4XeANOO$I;`b=l#Wmnx(@g^3N#le)n8jyLgzwFka( zl6oV2*9{)3XWnGDGlwWLt>8xT5M>GX z*g79Cu+trn!sKsHq?Lq#Z$sD#^M95&t*(E4b}JMnuLz$1D&&iwUBI=PG~eO3p-WM_ z8;ZwSE(SbsvOuQET}+;rHUG1|g(GX2=I8qFj zJQk(ye+1wIx3X0`lLI;l9P}f`c_OD%e>gAM05=TaOnaO+Nibx1Jqiy2H2=}3N5X62*+6EAoYcyCqIDj60;iXNT* zkcdI;k;hY3!XO^KBPbQpaiT5AmuLGG&hr+FhpD8)$&4p5v+GXK()&nQ(WDT@3+TD_ z(F9_r--RoA0ikf#-=)H~Ckp@QepJ0GkO&secdrRI$3l%e)}N!!LxHge49p90fH{BM zx&FR}sb9a&Nn3W{9^H}S0qm6^P8Jo*JNOPNTLT){_J6=xmn6>fo|8!T)%GuY4YaNU@EZB^RSl+HMAlmT=^i9*KPWHU(Lkgzl9eDT9P>405K~ zIUpkUrp|@G0cB4;zV^9^-UmU1}=!)Z^>_4*bb9#ZAv3M)kZ5R7#3{>Netoxi%aWfK^(%LAb0$^0pjgakS zjp3}!N7Txbkw@c7#Zl%oh)K1#KM|Ay{=an7dTG+2ZE17$Qq3#8?_m0%W;7aUmo=`E zH9Wyv_P?Z6NPNzgnb1zGgg`2g zTWs8(;Gw$N6A{5BxH?wAR=!+{OA80HZ;^5l92yyAG_JM7M3SqdQ-T}FzV7i}n|=ui z@2S52=`n{si9h*+ByL3MZ4J({r^1Oq0-sr90EQa88_n5L0D0|)@ydt7fuJC8QeYtp z>uHzO{|*%3$BX5RO=YD(yxhqsoSF@*7I9DKlof#O-Cd!EThHNOze~6_rvoVb%NaJ_ zbim6dvm4LK^pNYf6PK3Rb5yIOi7_fJf|lnd`B3)X`u%&k+gcvSQsLo8|GvfJvEZw+ z@N@SziQD6Nn6VN59FncfY@IGUdIaP>mb_VV>!KCBBIe zZ@;{rnC1iTZDWQu@{?hZ&zSJd*#T^1FIxKtljc|!ntOy&EK$2Uc%>K&T@~OR%zlnz3t_}DNe0F7F4DXKR zDTWO+;M2$B7a4zz!c*l++f=(=+|l+Z5tI!>#cTJ>1izB}Qy=6gRLH9#-hc6^ws$eG z&tTy^MLuZRmDxB?R^ZK3IS$o|Y544Uo>M(r5tOZ1?dgtr0-wGGs5!FAV|;`Lts1Qf z7#tqzha+gpwpnEfio zYg1$o|AhKN#!6#>^YpRZ2OV?*_djMgN_d^&VG)%?U%fRLrE5HEVlhXG z$%7Y&w@T3VErpHz>HpU6Y5)HGXF}4O)hu3IHoHmUA>*BfUY#-lj>7jT#vQrX@$%kP zkMv?lbf;r+rc1{)h5l$t{#f*J31R#y8~|h*%j?k_hH&5YXRGY5N@ytav5wVK0$qCZ zw>J+>K}4Icdka$wyjy7})9K*VXslN-p`{e{jUXDy*@X*>F&e+TQ>PzyGoI} zD53CScLw|@J-TVi)d)EXA)R&AeWdxiPI)DcWXI zp#JnFIkA01I8#k~Lr{mro$s^^%#eK0)L~=QGq;M-Ba3Kd>X?bw`$HV)-c%#!R^{*d zFjB7F*CEw?`oU;f>isLf?ln~Soy!#;3WEB*VqB&awqVga=zsoNDth-@XJyA(q01uQ ziK&VdR5GD@oOsJ0zHf5UM}KsOmkjg&7K+?a=*R(0W9cwV(G3rL7Zwk>MY`sr-43`X zVo>>@5lJ^XSof;1A{-6P8V;S<8xMJ3qJt01M&a76ah2f94wxuaFjA5d44!v*JoLXr z0c*c{=Iek|%#L~C_j-zyGtJmz!H}DX*Uu7)&zk1oIaMjWRua!jksx<=X-^=qmiV!D zt2=|{l{xobzg#pM3Yxrg#1}6fGK%RX7zuQ6A#>{jdp& zDPG*|$xTLGvIpa*b;ocZ(;`(}p%u8f&U}{9Xu#oik#CNL1$fPg?6=p03X-2ytmz7O zCg}Wi`F2Zq2o31EJ-*SD;@m^uIaiKhDE`j(;6YpiI#aw$dNWatyQ-HO**!-vaAm-f zbEg#!eEQDg$vXh$MSd4vZWUl2SAU$CSvEHF9d;CyD8rBM?#kK^k$gtY9cz|-I(TYH zl1wx0HOl!eE}zV`L@9#*LTYpXS~v#CT;Ps|#-Y(AY2g5rKQUzf!!#8>guWN=ZuP>L zwbVa_;}*akPAJ~`We8R6p(rWgiC+i9Uj_KsqL{PXmT&Ykcz-uh@vnm{7(JL09h}ld zg5TR=;c_k9+;N?3PP9e0M>(=b_Hg6a-c3c`qscgXxjDmsDHHfATf%FmJ)o}S_p$rg zim>we(>Yu+!J|AfTNZQyU@;fusjx`mHl_yDa`a@kjSFQiMS;v~t~PD#mLys+Z|AULf?hb-wuY5)I>NydK|q3CiA~ ze&Zy+@8E9JtqVeWV3JB#W3tN}W@SUM|K+p}gV@32S(AWUS`;b93O?L$&(&%L(|B{yn>+ zdlzu)uvgLKC88wvk&4AoPh8#Obv=@J5Fg*8IKmUU7u$E~E%-imf|~FLy52u5;gX_( zu1o+As&;)7466`_%!`iiJx60;;IT3L8A3kdwSOB2uiU`deln&njRgF1%GSAPJOMAy zyGP0{N0a8%-S2ox#PkT)&_oth)OS32ab*7(MpPw?Ui~|R z&n$wN1ve}zt!q2QLlXRsH__9+V@n*Us*qTLT z?)b}N&3gN8wU?C0uG18LS>_a&W{z=QiwMSn`ubtZ!Bl9p`W+T7dJMM9gi6ZkIME*% z-9{9HVPC|Dp~q{ax!G)Aa?55FR+%&t2YOpjw1nZ+Hy1eSNighYozmSSiZ_^ov_G)g6Bishoo1hw5Ff8N=24bkg+5D5Jr5&0 zxa!?JV+obG&+*B$1aC4(q-k(o;5v+5iM?M6l715$W`u8EVGkvKI4>_vYE6NRP@fH>JgWaJ%8p*hE5V1et)9@<p|M36z;2hs=)YcB(QwH3J7oSE&k`z zjB^XF>>sR~aO`6fC@d1j+>2-Yo0P4q8!=Mq)7XOzH(Y!1zO7)x3f<<* zjt`h7;9kCEH{XyYpR0 z(Jr8JW~KygGANiaR8$g~w)tA^!qN#RsZ+ZLObn4>w?gC{NflU5dubt36oiF0b27Tu z^03TLwJU~N2Xi*2JP7e_c;`(?G=C2rJ{T2iu%bGOLj!FaYqL=pd9?EWLSqbmQn^IC z>l`~gD9m1piY`tdNoTspMco`jeCjbhVB^Re!TIR&d!D>{;!r5DlN$IzY9 z>(jfevC+}lk@ayc-bnYCscOiE7&-Ul-ApW~~s&<2sQv`#2Qm z9Z1-Eml-EQqfHEAm#I5!YlD4{l9)MZnQ_^n=W@@|67i_Gz1_{)A>!28OZ++`VPN$A z(=QEzGZ=ue$EToNNL@X>eN18y54;K5mUmRb;h8mY$7x6CSmrq{UO~jE50N*I+-(Jk z^zP1Oo97@brBY#O?uAa{ZXfO(<-k-Uo&$w{#Ngc3uV21MWrL91EorV1M5<%sr5 zVclDj)ELPi%dQ!v**R38?1z?w#iop#~7hQGW4>{Id;^Qjcwgr^+s0;msepa zp>TNE}Uc%(s z$<#hLpSRr=&=3lTuuxCdp$w9TKK;6(laDIS;KFX|G;-6z}-R{jzL^A)W+`m#LNX~TIO3vRB zM~*o$ResBcCTCZw+m|X~+}ZYKdh&BnFY#>N2nvMqvl43`T#upwk?Q+Cr(+=J^YSG9Gg0oRok}CtAF&gwa_K-}Pubcx`s{d1|C5ez*99be zm;F{@kVS|JI;sol?S4Db2H^6-$0`1BH{ADck@f7HFYw;rZmI~3B2LkUe{nB~B{bzF-mE$M3cYfD za$?ViV8f41!w81N+Vh}Dx{KX1mN z*TKKUE*3Yq@_22#WiAT8dhC7H+SdTL)VK5|C*Gm_P{d*K1L2t6`}*0k&JbvM$X|#s zq(jzT{`ZbSN`TgPzE=F5KGG$RjOYGxCiGDCfrx8j*c~n*Cy$ z^&4rBT@{m|Eo%uprPRZc!-DYIl;-fG%p#=uO#k##`xL%g|9gk=i7N0Y(Kv^7lJc(& zM^`6$E%EH_^^1|ER=D!s^LlSd15~|u+V}2xBRumG|M#eGkoaKw-bCj0UC95rBsy)6 z2S`MS-0OT&2p>*+8PLu?!-t)*4CZBC(9!zq(wV2WP);^rTXE(EdR(tLc(zOfg`ZZP zJ2bXV`Q->B8YHV#=k8B~QyHkp&%u^}XVZtK?`IS-^f zut(|rU?}`66rSn!i$%8S=}#H8)c8k7ZGbNAC`dQ@v`{+fV}rxe@Hb5>tYa$VCqMF) z5TsfydDC%|ur6|Fm4>*Z1+* z()sJ4I=K7HrKDVZc0krpDdiO;c&f??=qMt?Ni7QhU>_vxa&>At8HUF{2B)!kx1(~` zem#lQCY&l;kk{3kg3Pm0qCvmK@fr8SI-i>p^5np0BwU9?j+IP6V2<-KiZu5Nb!#fvvqZEpKaqcI>{cYD!*t(s6 zS|&FHgs+d=^E$_Y@UhD8S8e0*Ho1P#zu6_CgSwm1ud!u9@*$h|tM_%#Vrub5X~knq zQi#xDAo&7cn9R?;y%`3R;hzLg_9noe|<6>a=*)4>Kw91Z?**;sM!)+8=CmzaevqScS(OmS>ZMG2M(Jch^w7d+MlC zEomM$)b%`N&)2<}DIM&w>N!dHlyiQ;v^xc)$ek|MTyelJ!5Yh!+A$ErSKvvtP0D|e z&U^%+HHK{?LL)Qt`b%bE@tF}N}_k4r!P96@h_WY6=y@vNDzlvX{afDCt z-Yy#~u4ura`E-h_mUNy!`&RC@Ezq|FeefwuLht21t$T`VgeN8iUyqNU#4^u$$_M<0 zD5{%Kc~#gI#?BittX=v;eCvJ8aMw>-@Z8Ru_%-<&yY`)~N_UFGbK(!b*tm*gecp~m zgYhM7+Al64_}mt7bkMMTDHU(Kw{Mw1&q{N_UJi5`>x;;)!0kE@C&DKuEd7AiNoZX>#wN3Nu z(}T5F}sy8w~wC4}VXt(psyD zqvph2hW>lDBUdd95c5p9$8tTI5c$Mb+BA?3CG#QzS=P4+3um+y zgyJgTbx^pmj7u7(x4$;tU+0cTglgwya}B_bQISK#FN!Fvd?Kx2p7 za(9_nXbn*vPvuvC?+{x~e7!K=-$USB`_er0BoO>HgD(nt-bb?dM7*Z@K<1c~&V3-27r5T|9ypC1>R= zC$Hd1tsO_HEETNS7*4Mv`NXX)pbeP)~3$AiGtK2|#Z#T(O|tkB-&BvM+As5x?rUo}!J~BCeLs@L5%> z!w~r&=2KsD;Yaj8Zr|sKsiLfB%Kn7Gp!Vh5JLlR!VM55xr6d-c1D>8+^)iI~hWnJ! zy~;S{*W|iATuHpq{K1QIZ#to}S?Rl^fIVa(M~BvJd$^?+8^Wti%74C>+16>1jtz~Q z#;I3WFy!wcUL8?VZdO?0yOq9Igqi(kPwVwC;Zko+QgLcJc=ML(Yk)USIh$O(dz%Mm z<#%pTa?wD0*0QwAh&6~B)Ux~Ey^B`XOmxDWZ8&a9p5~a54Ce_t!X{p4;9J`&^N-3^ zq8!g=scd&W_K$H>xBUr*`E=g<^n32Z#RAV-mx{~ad_~yp%kC%w8QUkp;zSd|F;0wP zTcO2oC5$Is6v^PM*T5f-k#gWUu*EMEm5y7Fs~lPnlk%JIZk)tx=D@ko%#fz+P5i6k zo_&1Ko#6E3NB^3o1F6o3>LgDvgVI=yy0_nT%Q*Fa6k| zSaQFH(F?9E_xi(8mF{7p@`ydw{|WE;oymct(&E3!A0NPx#t+-e>3vw1;!tH=nt@M7 z_i_OD1SZp$=WD9}aQ(KFCTW|2byQt(sc@#p%8G`}+ zA!x&l9LD&&0G|iGF67z5ahj%R#}7$F2~SBWh2L#N>5g&QPG&cF%%S%?sW$*F*NhgX zpUFde`&a9yf-BI(#V?HBA`LXM5AEkB^#v7o`8@*(%&2&2tK)>hB2nwr%3cRkPn%lb|@r5?pWdV}Fn4 z)xsKs{y&HZ%$?OQ#9x8KWYaW{#{+@NRk6x(tp_zU*@p=la`2N)G4&9eIh^?(deqs> zhv0blYA%&U4uQ&V32*!({crqi&+3LBff+r=>$#_k1eMG=)#87(gp6M!uYGM(2;+vM z3Q4I-1O@dUbfP0cNGmL;a=+*Sz9LpSWPGkCZt#SEjDEUKsCh?rYI;W>rf)`=bpMFQ z1AhWJI-I8UHgUwJ$8O@YLTJnqPUMSxubUPj}jytv5uS7vqn4M_j--erynV~AQ0 zh|F+#gl||2^n>a~F_v+QV6WE;o8sCpeoh(T6J6%tJ9~|xb9QQ0H+2O5uB`rGZ63ki zxyjj(f3~1~UF*+ZWjDybG?lpap&th4Kla`>7=uKuvX`#f$(UBI*Q!6d_H5L zgl^lfb+3*(BJaLFh7d#2Ic@Aj#*+4H(EDlspq=kK!JEfEP~qYZLGSxUM!9DYta)D| zZ!mNKB&;u;lJtTBtt>xh8cW!c_z>pPl|nr8?}^3Ku{1*Gz0aN%ev0_cibq}WjS>{; zJ5q0{lk#@bHAJQPJ@NC`keH)pdN9Q<0Wy1YWGDZ?GKvE(SGB`?4B$Nb>>(K|Mb9MA$KOo%k%U8w~_5k48LGAv7US9_5jJp^xbf1$%oYs9;%p2PO>_|Q{EZT$t_QOMzHn$_IQ{u zacb~r$ge44bA{cH?K^h}A4~YINB@o{zI`F|g}s)vkBg{jzPI!QE6LL|YCc0m#l(fl zcE(U*ex-4zL!}dZ(DqC_6eJ7>gc85LXGulP>wmnjAId_;q-e8`@-pyfdy?}Iy#l=M z+m03CMhK`jW@>6`1Zst)H;xO>F_k_4wmFqMZYuWN_+UuVV@_Xp4kZYn{KR_+6~Sp} zQ*k&ws$B^YMy6Czl%`;JJJ&OQj~*T-Yg@e7KZd5kjZV#;{V;4lM#Ubi3oVp4WuMnR zMJi#%q-n7}Y>Cwfub3T&)0zScnAMqBN1n7-b-PQ})M~v|gH}nx`EV z`Uu~J(-(qQSTI`odbq_NRp?-gVOZ(N!2GK#_a!Tt!2UyjfL7@NJkMh%(cB*fVUdZS zs)f98T>Ki7j%*wnb8Xr0j9Z{5b!U=(t_+SyF8i%^u^>LURyNt33=Q6P8_b&lxNgF+ zalU*HOxZaxE46(mo;*qZB|Nd4ST6r%X1Vztalm{yC0r#G3}i|sR}>QAFmKlOjg1l% zP3;r<^|A~fvu-aLqwBY!sXSZR^6{jPc!oi%Zta`kQ;uRZZgYyUs8Zf$5EbLSRx zG632;t22Fa#l)#c6gy{yiijhuKHQvg_h3utF;n2SDikr(-t;4_(>bTV(Y7=uBrae2 za6ca-8i&rBHB27H=&&IwGMf^}aTB4wMP3Ga&HKYomRX?xNpb~s0V~YYR8L^yKaRuu z6$sR`ba*~((}cz)2J(1s@6pH(2M@jhX|qeKgw>_>gEVe*pmopdLwn;RT$G&Ib~ zeshAY{v=<=M5o-#Y9eev#~O3lYP0}E9td7s6qf!l2ifW3tEl6B=z?1PRvJ!AU zdO`Er+Av`@FU@zMx|2A%#mU>A=?#O;CEj;69MIZ4yDB*@81F{Nt2c^d;OatweNMYB zZg=X3ZISX$q&C#OE=DtB@@flv?SWlDPu0tJJ~s_1=34oickqYr9)Sq2h4I!wuB>f&1kb6 zMGV^Br~QYt43t03_=gzg3@#!y@75` zI8t-S=hk&nJ`|o}NXhR&#@)VTc|r7ebXCuJ;uQ-XOpYDLF%QshJY-}yRs#$^%}-E$-pMPTbDSyeL!Bj(Xg6A5*_M;~HDQ zL~fBI`cCF2kL55cQO@?GQOnzrJaQN*b@Z7*X(%E!a@p@u0gX<{Hj*H5wmqelNg;DeN z7VkO?I z)4_4;|B-gyk6ixW8&{-Bq(ad^rBV@z)a#T@WMoB@k-hiG%qBZ~?;Wzo>)2a%Mnp>} zqqG&@yYD~n`Qd&4>Nl_Zem>86T<2WZ(^wrRQxd~lRnzPSe-aK^gD2SD{ z!|xLDq90jj$(iipY0P^T$dwjob1dHnvN;b$7O#Z?|C6SdbHY7v4~&(B)(;;EO&K*4-MGcE`YaRvLm&<;gY&0$rp<#IGTzhWyv zR|vt|Z0Yw?Y{#zw+jWaaHb~5oIkIPayD^A|YRB!@&(Vk@U$ty^3+5(MJ&5_zhCT-r zn^v`2$Ro#i_U10vkl#(lt$!l+-$Wg!j`idk;l68S+d36%fukmPs{oxaijL+BDp?X9-M_0vpHuXH(aX8=74^Ygh0e@_9OSiEq6qYc)Rk!d^SGpu$pnynKaw z*sQT0H3Nj!ja9nQW3(aj^T%Vz@SdSo=i7PwI(eJ=z|MTqYO&^S)E)je+ek85%a#}3TJNTP1X(=GDKf`Kxs4qCvKa=Vq`0C@f z`Cx*t!i0#>fq#7U+&$+z1YgAj(fsAc&)2a_f=7BZRRifMJY@gz)mnE0;e|ggVB_lI zqeJvjt=o3K>m&N_89qSFYzDp%k2RXLi-y-_?qY(wzXCGNY*ep(LrSw~OwA75oK46i5nD&*&F zh;(l)CXK!O*sT0uE0OysGaW#?B|y+SqZ-SyZbYhPKh5di6{hY@dzj8 z2dl4(<%eN$w)0OOg0E8T5Ocn2p9o_bRtEcDek3<^(0JdQ{X{nGj6d_4;HySHQVbQ9 z4`AiB1|h^44;cdU=;tX0zJW3rNs9YH9Swj6WzVuqXb{=QmDxp+@l_@JKfYRZYQBu% ztKhr*?bfeFD#YTofXcdQG7|&E;y=F1$)Ouk#Y6a=9ow^NMetRv$%4dP8!>1(0eKP$_LjgqK(ft6`>DZcYWaU z**gJ~Ej-tm9V}3~{m+Ho;d59NCA0gVKJ+whoVW3N1|D1F^D`v$Ap!QDT{_SCk^gK| zqc))rkref{2z?07Et{?$A@rd-I>`rwK7^dF)m7gU`Vg;?b?D<~HqhY7cjTWw)UNkt zh0upE`jzOiO#3idMBwd5%NtuDedAv1KYfVz`ztv@AHwz3t=tlXK6Fz^OV_yE8%=8> z!wwMokW$MIhMMDqKcD^g^ndzLJX8JR=J+>KNKR$nuD$uBPcs_l8iGW~v~SOkh!Xmc zWA)BXF;qr%+MYw*gg#{O&gMI{tQX8}q4j@9=tDmZ#CzNPLq1DA40XvOKdvhJFt}gv$(PQds4v9e!7495R>;U{y-Hkq?wd(b(x^MY~x(m8_PV|eE9 zAeluHXet=bWK0`F>Y-aavO5$>Z>P7-ce1#X7C41tS_pnGoMLWG@Ovz+y!hVyp$j>_ zuq0z5yNdkttEBbqZAXDm+VswIhi~M;xQ-`O1izQ>HLZ#nyM^72)(-A7*N8fk`n>?H zGyV!TfAogn_cZ12{_%SZs&V`yL-70gE3q7YK*@K+Kg>rzSlBnuo9D%++< z@O$Y@yO)9j?$}?~w|1287x`k1c0%44I#gOzEdR&vOV|2kvs@CONQB{a7Qye;y1cjP z8(o06DZ{t<2!4OsBvqT>_YmJ6x3P!d_oN3>T4A>(k?l{F@BUv0f!o=rZI2b~gL3fBZi7@Rgm3uiuc~oBsXIMezFq#+Z?rA!Zy= zJ?Hd~-#qZmG@5+4H`S7Pw>y zelJ@0N#z8w&sv^5dG2?vKIDB#Gie)&B6+ZV@8Xy8C7I?O~1)ll=&9#W4-EY_i|+Ga+Ccs;{q$m zuRmNT`2Dj{@d|so2AJJyW&4lcmmlFPCHOt`cp4i0K~9|sGFDG>br%v*g1#TXqhKlDT9AHUz5abf;G=^N>} zka^Pp!S91#D>&YiGy)BKJDY#}es%EfuEOhdIBcORH%IV$&e^k^{f+W4Sa#;)KYl;- zOI*7SlThZ|a_K*Qe~fOyIAdP{sZLD)uJ4n-WF<|nPTLwaWarLe`^WFEMGM>tbVabb zBCU6i;P;=Urx$OYB61*D@;ovKe$R0GXwzqJ1LV{S5=$WXeYwLBU-WPlDX^9|dH?ZD z(rIRuFtJOHDCMw|@(#i8{Ua8C^WMvZaan`iodmzXr4lV)bom%4o#R>l$M2Q&)0b^7 z#gYpSd2BgK@cTk`xh{g=V?OJjMOA{|%Z^dZ6TuPKl?NatNhCJC?aC%p0@{njM;{jhc-e0fFTAHNR_ z7YV+fH$<8}vTcw~>Jw=+Zer1e@Ke5>Ywvh|k25;5f3m4LQH5d|r8jj6exLMnGKyv0 zAICPcgm;`(2jv|vh6#R;pR*V<_7nX6Z{XGdg5RTtV1cV9!SC7L+DfT*laNF3bn9Pf z8t^`n^8EovB{Y2%_S7QyeZJ#Vt>7+6C~{9TdE|W!`7i3168s)$EX2)}2!6jLd9n3U z&Pga$rx1Ftvj@AQ^Qo6I2Vm{A>pMe&-^V}BE(U!&6wZ{X4MV6_S26|I#7&J?xU$=0r>I`v9AP z{@Wa3n5tkFagpHn>8EK*(<-9jv5sfyKYo9-!)7m6q8$3u{{Hok-wW@$q&0jZl~hx3 z_(YK$!*}DC69odk1i#;7{faeXUJ7iC zI=%k!`zwRL2CRY;FsyU5=^wwpu#(BXa%q+Ha@FOS8^P}zvJQz`P6lD8)a`P(fxfdoP>W zKTKXZc;ST=izd`j@*ivNat7ARPRbc_MX+bK?UT=_Hc&F=R8iR|;dh>02TmpKK%s0i zsr;wSL>_|kjMJxjSk@n7HUH#Ea26|*4zdg8GSv>U1t?+v?42!ZN=jG(1v*BdFMwmY z>ClMU3z!}dWRZ0>!HxVCrjUXWw;U+#1L zn1o>J)@itSFTGiYp%ZzYoIRVeY75EbN?ZLOKZM0Y;;&isd?7!*)fb5b`Q7fL7TM>YzOTR))XFz;7#i&gz5D&8h~TR8U6!&I!GhTOVDhK1N*;M><5Wi8?yqEy z7K+XKEH#u9Orb7n&A>aJvDc4r#ekQ%p!@u&5mNSPZ3qUKfaJd6({j&9NZGNZOfh>5 z#q?5x1j!3zjh)2>H_EawE%I8z-cU>AxLEV{%66F!C|XVz(_$0OhP0pcACl#W>GSTdFUZ6=>^B#o=cM<+myXWJBthkeSI_QkMxZEV{Snt2 zqLA-Hz2tQ$9F{mHFQ}WwlIU`4)@X7TNxGMd+;-jYB?Yg=Uo0z1C3#Hfd{nVBMnTYe zxg-~iDYlyPdl82POQVr4qe;o#0AAR6Zq+FEB01q2;WsFXTJR+&mfb1eiGATzfMq z2a{({GOn?SfP0;R_k{Z(Qjcwcdpp}uhmlqLLA4>arS$b^h3G;)SI5>rEiXVI$HV3! z*5VW_^JWU;SgRl;Ydh&fI&~&&w z@nn4ra>piL9BLQ_#z4;}CYv3YA^n>*Ia z@u)BRS`K{qq_j7z?gy!S+@EVB;1_A+_*N%rF(=rYa3JVzP%wDAPi%ep%?f;(UGWLw zI~i)Bt0e~MBu_U7-^zq^GRvMG@nvd72%`x8e(Sa(%F?H%hGd9f442^7A73H}ov*-O zUxg7HHX+EtTOUr>UuJLLzDTC-J$F1pFATjMyK5hBl4#PI;3$|MA0ufo!H}ymxn)?3DyrAw)_%QeEE#HM3IAHwab7SK# z(!T4teTUUEq2hs-_v-1#Xg$qskDs=Kvyi};)Va^(W2&~gw+}UwthzQzX&s-F+{jK# z=c;{Cn=R&|FSGztS<_P7%t> zaxxuk1c}7=0rh($krT~`B zD}--EI?eQ`E;_s~(V8UudEd4dPnvxd1zm3Q9=%yl_%qlOm-^>2=A}!{``D^uS+rACu%)#x$U z;1xbB{3i{{nA?OiGKt)nQ=4K-+eSfZHuE4Bozx+iGosVpYZp zb3a31pGUsz&Yk&4CI5=P#G?f$b!zTqM^)g;}k)WV^^mNSg3gzv7$BY9oo`?RQ$nQQ}FUAF{5~-z7 z`f&Bk6j=?vW#;ewzF>!k&r;i7O|$}jH4CXeMq9Yt9p~6Y?CqRUDX~0DBZtC2+Go6P zC__7a?lYbj;Sgvo6yxa0vPx!b#LmlBRuYQ{PHO;6B(-L&+HV;0<8n@>`d~D(A$Qy?|pJ4EJr>3reWQP zT~}|9jok|eLHg{2n`7k!->WM(FswnJ)V+1_LDg8f#d*tzTTK|8bThbC5g|2>U0~9s z7XBW5L^FS<5EvI+UnvvQPRHE06bl)6VbcXe)9L4#a5YJ1;ACb6^4av?ze7p^0q#_B zk$d@=dw=ZVrg#%%jxdk>Na#f~Rz4|rS$D`~NpY?`lZRt1{2uAdrI565AaCErZ1^pu ze#J16m}`wO;nIL)=w7A6|LP77O>~x1AvPe92vD-Aqbv^kp!% zl^ZmG?^W|L&K%w_^4?aJ;Y0v9EM2yu6^O&Pb^{@^_OAHliq2r(E*H=zyE?4Qrs0R( zio1u6p22yDr8YA5#9oWeI_my(G|x3RkQ#k z_}~9_+1&-6!Qi`lY?YCr*;iA*UtU`69OD`ejS9r+t&sc zy>QX9qjoU#90%VxBcivnKL2Hc%=6#B3$o#@7?*vUeyKF`XklH?C!kz&2J#U)_u%E9I! zm=1PjJ`%3Y@wm7w`GM6i8Arw#HnJEhL8d6k+%Gm2v|O{-{Z9J8vmKmvXJ#XSQ*g~M z?iEqbUex^b;(;@s=bSIgP7DVU+s%d3e*z)2o)b?H=f}wQgw=@ZM_3us9z+`-15ms7 zsoe=*IKkAoWyhum^7XUIr+nl9|HoyO_MXnL*SjY0_mU}Uzu3KIA*6!>oC;becBCM9 zwf>QnvVuE0=6=q%mGFaJ`kyRz8T{p|L1j673-#8n_Zq**$6Z5Cq^o{*s1{xG#_6jA z^jXyBE2R6wr^%BBF>TrC`Q%F@MWZR`X}P6tKNtjA`{*-mJw!pxJ=q}Taun={Dm;~_ zMS_-$i*ff4xk#yYis?;CG&nCad0%VF!nTJ#9pA2+|L6CMO}Z{(#w{P2 z!@1_8T}$xmcC6zHjX<$KjB}>cL>=wjsU{u}0sGry4LSndky}J}i`e-hQM^ zPka9U$ds09csi^TM2_!>NGf-Z&Nb*=`GNi zPs9~eTfyZjzFo(eCNM?wh2rT$qxg6dT=;#bV3SV%s>=ChP@8_#EGwUdTX<#Oy=?Ww z@Ee*(_e}L7JH36L_%9+)RPm#b?|nzi9*|1zGAP8SX6ZdzPDOCmVheA!y$=2o8;}1J z>J3|FsjNy3JaI;n;nv=I572(PaQ49C2N-C4eNHaP8e=WD7p}~wVQ<9b%Ndp1kV3Z{ z(43==!c1FBBaic8xn*ZT(1Iss`e`imAH9ULyLX&^QXdQ^KU?qD{c^>g!%f4HGEc#- zWq$o}ZWNq~TANmQ=YpbNHi~{<@x=QB8!BQP7lDgQV|Rn60LbtO<~bY;MJf?G+jw~= z^ay>sGm6m@OZ*uEdK44DJD2&T=7j)IW(~P^X_^E6IOqR4ZyAaP{;%b}O?dt1_lrPp zHqD78$U?__ym&MnYR#R0#xuBr!Kbdt#-;@Dqni2DakCW<@1bbuH!Q=)tMSFtR~q29 z7WWnFU#VazIlg20Vms(KTx|3m&IR3L@AUnO2Y`lqcPAqdbNMD@L7%u`d{oF;z}L|R z#=ZrOA5zP(bi?w8Lcw#i*a#`6cu(y42StB~vQL0`a{Uk4vT;1#mZDHxGXMuW_LZEx zGYYBKMh>dG-GI8GXik?CQ+QPJE1@2GLJWt&{&Qu1kR15uzJ9eAX#P19e!P!3=hdV? z$Ambd1T`!7dr}Z4@0_fC3Lc;~XezcQ6$P^^Z=ERmdBGxM@R;*>1&n==d-ilO2Y+Kr zZme=Hj@0F-S7fxHwwc7r=f)aP+^}CPHjhL`#y3?j6PjUTC7yguu^Xo{lD6?#xnWmj zukogH2Xg%) zA)p$%Q@MxmbGRU}ZzY#D4Cf7!X^XSDI7Y2u7p&n0w<^vmT0ORe9Y4$N z-4OCY<%~nr;m6!C&N}nh%`3!S)Mo8=TFo%z&i<3aENg&bCWp=s3dcaRk4}q(v={ux z@{7XKiSp%aS0b8;rNum@&V{4OQhJe(GvFY*-#!zXQ23f7Qz~0T)FUCcl$|S!q3BUA zS2cY)6lOl0id&7sp&H#5mVJf5(X>D2>DCgQO4_Y^b0`Nk71x&z(jfkg+1^c+6#=$i zq_a`516b>ghn#bo(B#zgk+M*0m{YZ;J-g-zLc_YM6mB`t&3E^s=xQ!l@;`ZaLa7e6 zZOdCTIYP|)^t<_n@f72;zDD}kf>%ph^THy?Py=xvGJlGp;Z=Vk;kgeN9f2jI%nnm9FD>zzol>Eun(HN9Fm`gnmdo7x6{S{BWw6Z>+x z!5yc^u9)E^srQ**R};{Bql|nY!4F#-Paf{nPKWxw;zMQUlVD0q{$%COGdj~_yxOWGf9!I%I+PXpT#NIoX#rySRVR%*6`ZJF_SSlL`N z>68c1-eL*)d!rSYj~{d33m*XRbBw0nl?vx$PuVK-_rT z79Mu-#ZNUqhVE*`pirD%O^Q$&ewtp{G1gHEH5U>?cbvM zz59Gm{))iwPKP)9gFN8S7Ba8Crw;!7uK8M!Ith(WOkWtU_Xf9e7ETuyFPuD_^Wh^g zx9>&&*S_|SGk)#Q^nZ~M0zQqcx#}C?c%JIrRLbEf7~`!vCwg29CxmSGOsU>N3O(&W z>j@De-=xSuA5UQb^%yJDpS!s0<>i=aKP^0*MR{U{{t?K>H!n3TXn}I~u_IfZe4*bX zZTW_fBJPTpoe%LZg4d#(E#l6RP>|BrCg5+0T%B!pjN(L|?x{}~WO53TtLw?77ZK@D z2vg~4f%UV)_U+SiSbRwY^hdwyIx0{~!t*{*F_{es6{0 z^^kAJRtK>*P3n70av7c#fBoh~O*M2GZ?gL|<)OV&5$$TjYZRjBdae}N4epFW*HV)E zVUS@vDNL&sJj3X2Gw~39v<#&k3himQwpz9QV@Dq<-1d&P(?@(}8}-vMWB@(eEsceO zszK)V$wsP6g|K(#TDH^MRuD~Jz4GKjDfrmEe;#*_ z+Fi~CSN{B~LgFRx*yF*Uj3dN%P@hPf7+wa^(b9j-Sz$6vOMnXc4AcPV0U^EAmrZTuO+&&wyPg#1BMfS>zd zOgRkhQ5p|OwgBxLd{2k+o?^Mm>gLn2Y~X(9;ya`q1|C=6=ta+{Lmlh>5{;PxSc=}U zC=nJ)_@*C~vc2F%Dhf69kwe%s-up#L?2)XGJ=7IG0==zITPl7r8?<-?%#;l_>8jS{|8% z;(N2N9fw3nZ4W4Q# z2T``m&fA5vQI)MbUNx}~2J|`0uRTW$wUxdXTwaP|##ujpd@966-J_QBli6r^lq-7S zLK=LUnOO4Cbiq)!;vUgR+DlrCI#54I1qX0u#uqzt4;Hw8E?i8(;S%sm1NnPDpNFTsbbof1oHj-|< zFB_)J!`bkm6URabzb%7hCa(RDV3{q%Q$f%RZ2g!kwob%={P`ZPPfPyLGb5|Uk?x3L z7W^kdbRNK!j|<(0k~6T+G}5pz*Bm|Hw%fVK+vBO~TV{)rfym!kyRiDw7cTDAnPl=O z{3liBO#HRHFyp@4$C&Sg-_w75uC%`0w&I_RTS7@U2QSru@z19$20Mwqk7A!gdUOPO zOJ2{v@goByWp>6$RTtyCh4RBW^3@=&Jm}T@y$7gVdmn3_ZiD+d0vr|JsvxhxCh3uS zC!Vk6em%OS90i3R>SgTi2mPb6p8a0WF~Ut#H>z+HXObm9a4C%9ezt%U5)woX{5W^M znBog$XY-QWF`fih$?sX zPQXPyx<)(i2s;Izw@QhILWCGpEz05okDWG=i zvXt=kC&>Qw>-)uOcPPtVNq*E2hKWsrgY-7aV9U5rb*a=EIZpq+`;yTZ$i*#F5i$n& z;mYq5nsr|298TSIkINB6_+rzPulfJy`|R&9<@r$p0hPbUhu+4Pw4qZr3#Tpw*O{dRW@7{ ze8gO8QVRKDACEoyQiMG{a$jd$zH`%a+8i;u4b>5q?4OCZy9{Sdn;)&4qHpb0T z=pO#G8u2?6Ec?UCbW@ zVK!!OD`T`dIsl?(+_e0L9eBs#JP|pQ4s5iya??X|u=%~@pE_xHja)T zPH9M3OhGx9U&UXKP~37#gr%kWIZ~TvKb)P7#H$rg-zTdP{@}@pcW5QUAe3&C`f-j8 zQhf|KsLF1QdE4I2*D)8ss@XQKv?V7z)oPzbS73w({yw~MuQD4;M0jhrYaRs4Uz<0Q zC?)Vkksn1ojTCxN)r>l1gy7Ll9s|Q>BDdKysPM-V4~X1*)$=pqJNPv2tl9zf7+ls) z;okQ(2l!(AuB1Pb!qqEkwuw?^xNX<5pmM7aR8W}sMJ{*-qH$aQrpP9snu|v6jve>m zm}TViKMaIVqJHtiRyr$ud+(Lj9rtLs|6oQhf%6afKOSEc!y8f4lRdWJNn+Gm4k6|V zHUpMuBK+V~+Gx_VzB=f;>~LSWyA9)&?&q$DOe1ZZTq%Xh2tH=d({DU5h6cXHf2vYD z;f5TqWbr}|{Ax+M_WE88#8=*MQ)>-`TMEjLh8{FSbH#}e)0iRd`^SZ2?hj=&>LvJ%~&?%)W0OR#z_QLlZ^*YWJ}gR25;NM)1&b>@XsF{|Mac}w)U z7nL`jGpG_=AXXg8-k0UpeDUe~m)iucCcyQbLKY&+4={$@Nz?l# z3M^=EJ}k}f#2;%L4zCHH!i;MAj<9VRz-e-)SL}fsR+in1%UnqM&-Wv5#ii2{<+E^7 zb1Li0fj)rG3%T~k>p*0jbxUHG7k=F7Z~Wo?Fx)<~#r*kGBA4*h!|yFGI^d5)$hQTt zUTod)w$fj&Kqj?!nz>a(j)92Zp$%eRZ`nNA#W;z`T~9rK%h;j~>E6WLII^n+em!q1 z+?{IxCn_8*9aekro!WK-$A%&UN{7Uw`j;%$&vS8b`pfmR^^Ixpxb zqmTujeA{tn>9qlB&FlN#Ox1v9Ri8Kp^}9%Wl1iZ6#1FhB7f-xcdVp=Tv}fx(ZYBJu(8?Rm&>Jx zff3d9w=<-WQtQzAWR5q|QZ;S&QPU=JYR6s=M96_|K&buftPSM7R4Jtx_a^##C81%X zGQig*IdPgXSeAL)@+IMWkz;n=#y>F=Lj;a5&i?j?KIQvz&gW8amz{Ct6roG}*Yis% zeH!SvFV)Q zp3BGRm$iTQk^R7ZRA%z}bPWWnn{9aLW#U^SZ`I=MIm8@A9OXNoT9l5EF`>RxfF6DR zduLtV!aKP~l;PavsKu?9fbA3TqM>TAJbE0IcIO_ydtm}Iso2=!mYX2BQkVbuax6xl z%jtbcoetJvGMS>?eMogy{L!gnX&|z~UF}!r3bh99K`rt{Aj70_tNul7E7Eit3$$@3d>S*Vd?E#|t# z8b{r9tI1FFF|&FyMxy9Gq_R`YsOWP*^2X(WoZouL!!g>t&KHQZO(i=Y8>oRx&O|Hw zLN=y^wzq_+5Wc`PCC)jK)=)O(l_H{N0~BVm`R51XAuOcndf!nU+$U`PL#f{be7zbL zm{0k^YfBNw=GHLad9)#6b#4L!J5KlmC2v zahz>97sOPK3||87n(R$Mk)7vhF6*SB=AF$^`ggUU6PcP#SKfdT+``JHYVB%Ija6mGFbf>gaK{4xp^-ZxCBA0?OZJj@c5^SjsE1 zgHodrzi%@s&iPvbmwwNm_)R;CGS((CJFyTZg##ns+7tlaTyWwZ&k-<*SRaThZ361Q zNoRgl52512Un4E!YSvNqg;Osr#M}%8}Y}X zv*9Ivfu>5_bN;Gj^`*za`_OlInaD*kju||BK$7r-4&FxF5bFyEo-m)S2&_ae$6eo7 z)uYjBkS^5ga}jPf{EDhcX@pnliKO1O8gLAc`1*w_6;cG|FXXxQ!OIQvjpQOSUfk2q zb)N7;xna6ACABLU%?=;mODYTpH|rcZHk)v~TDs7lwo?%AJ>M5|epnVFw#4jLW^>0C zzcTzRYz01C5yjd5gb!J%@oL7Ndl;Rc8XIsq6sHQxj?}wa5mWJr^h( z;jUqOEUC5}AC7bJ4vtUi2Vrm9;7sn_>fhN&g8 z+B>iP_xXv>hn6%)z9eJT9-l9v-C;Q0bk|mPOAJocIR;5^`2m|S)TXD0;Gjj$#2|Ym zKB1U)QaznT^dGv4U*$bAp6yCaCg!G;R~T>F;-eeh=dZdKLG2rnLMDZ5aQYJVgc;IOi+C4iL6-(r37!Ok4O*421Wz$m}7Qfki^DP&BWI;XvM?kd?QYMxNAM}R zp>Fn+kn8g^N?+LodstfaO_$=^uV=ysW%yG>_mN^AwEbJH8nJHD!$eMM6F_ z_|<#WXokYtvyvYUmeJS@eXQLRWkepu;PZ}?2`Fx{MPvt~2M!B+6Qli4;M-59yH_jy z;Hf;_xZ&Z*|9n4wBh^*-j1qdmpkbJye+BVfSDg;s*M?DvDW!d(&w<|c!$L5z-y7q0 zbgsK?2sF#4bdU4D!l*WmgWQu%_}6~L*({mx=c3Z|C0mr>3up6^;e;XhSv1-b#^8W5 z{>s*m|JdVazMN#E#0pdl3#9*g3Q>M+i$;4uH9k*E7n)2NNBtea<3)cv;Z*=P!`y~2 z$}68++B)EbJ`GNfvfkI=(yBtiSKc=K=*4L*vy_j*n==$;rp=f;^=n;(r34k+7Y|;# zl7+tewcb_A`yy9x8{hudskr##eeA%&TzEv3Up8jM+$2TaD3@{(ESWM`yPSx?r?mC$ z$CWeTwt$=shjtYH{=rZ7e-i*I!h643vl$^*#q=evsR$^^S$;Zp!Vf((&Z?$gh=5nR zwJ)|TC}Hj2@N*nSUT8zHr(p-d_18CL;$JwW4&3gKq1yHQo>uJPt;iQ%EDdNgRRlU6m<4(bF z!c?wyd@daP*EJeD9~lCLd=8DN{2fsEWU0l|XaS$^_J2RnXa@1Amh)v=24IVGrKYDZ zVyeK*jFP?zFj?$L^YZb-?3Qn*a_sKIEorSp_BjP8{Sczo;`NZo{WeMC^hm-9`p+~O z-*wTpN~QDXDH*KYAvu5N<9!t6)dZhf71dpYgoO0~5#4yR9mC9P4(4wk* z|LM8|OjgGP6@LkagKS-vg^>|h@qx;I4`(UD;zqq;c_OavP$|yT*Mg#uNM0YJUk=cX zy>~z}p78feOQGBG-}T2E?tIqmf2F~?&A>nKnHW;%%-UKDyP|J|)o9IrN01JWUuiQ4 z!&17mch`yEcZBEWv#n|2V3XK>Ku97QwyimMEoX+~mz_;PtYO)3&!=UpIaemQ9p58H zbuSKULO!g-{tU(&)A~0u_oY z*O*vxFp^;-aemARy2Y!?>~6WBNJ4Xbs#O9UX1oD04P6sWV72vus; zUe+Oe*xT99m3hL0UoRh2N4TN`QIC44) zWT?76zJGrYXLHP}g=_Bp=lWjAdvWIv8!;3O-e&%C(go_hEYhiR(s4KdL0p)Crkc!v{N)*Q}Uvg-K0?D8jk+v}`;#F9_UswWcidx3LRIS9`Tf%U> zM*~_~NJ}T`rlIQ@*L|tyMnLl*=|uPMHl$iRKiYT467?$-#=p!IA=jm=QL|gpvCDu3 zNPC)a)7F~j9>X(C`u^yN(BE?8TMGX2Fscd#O}(r5Mi64uqfPw@-?&3F45i%ZF1@-`V;4N@$F}%85=keNWa6H zPY!wCU8LZp2u3cM4nItCfOm%s?ka2#h6v}9=qnv=(7jl_9mH)Ra`BpCJ+CS@8601< zdT#^=mpK#J%M9R6$!*o~*C+pT{bhdidRYxUk+%&*^38rdkV*3YxKx%2hkZk2US?*2 zr{(+AZPCxs=f&yMk&Z=h;Df_qR%If`xR`p=O>njbD^i@ zW2@MT1Bgg7T*)QwQGxpBre2?1!Esw*ri(xocJ6X8SttCJ)yH-@&D<-7SChNjScp1_ zYDjf#LOl`+d!krqY69T*^#aSJ--#$i+-nR!o}${w-J`oYyWz!m>Fe@cP1q!I(N1UE zBzzJc(^@$>js{I3d!mP0pkVJsr>^<|tYqGLXQvV|hiIs+W&EiL7uI9OuO+r)Q=6V* zoqap-jGv|xiznu0gHK6KK6S9u*ZT5>bfEvUg^g*?aH3$sUpKu_b#XBgqJl zQA!~x&;37i|K=wzFX#Sz&V9~xy{}!`7{NH#Hf$G6KXNKz0qKA!cDHBSU}MGF7<$GS)gaNc!qTRFkWzN!DHIuwlG zcXBfjdDGQu7rq}O1p<50{gb*~nJBxO{bE8p3J(7+E8{q)jaCNB0k_wQoVR~`d|6Y2 zEhQZBoSq6tQq2q4EzPH+$s30|dL#~QI3hM4NjG1Ak8I37r|J)OVx^z_u8TUavEb~Ih-+3eDu~#e{7Tb^Qr@$s{)rjr z!cebb`m+I-oA%v1pDuuO6<68m=Ld*<)U-mK)B$*3wC_KQx^@62?kMT)Z($Gbhe3Oy zuUAfVC3)D_A@f}9obn2p;6$tuJmpq+Wp&|U#o+BoCi(r$NH!x$_b*(Hb9eJYmo^7L-gXqhgA6XbQ@$RO3LFLy}+}XBmvYjme$Qk^iQxmDs zKDoTFVrLlGT<0TgtVE)ML5a?}%3x4wCa=_T!~wqq``CU;L$q8{9e=hn2KIeia<+fs zirds2zZm#Nps`Uz*6$1xf~&TxO1L))$3AqdCEvBfD?R-8>+Ss@aa}x@Zz~ErT9(?G zxV&+K`WI(Fh!1|)$Q<#aA;a)WU0~RtJ+6N;`XRn)4s!~tg#iPE{`k1egHsPIK=abZ zs9#GgN{5K3h52}bjlYlauRngc#(lGx<4F|AJd&BQuSx)?KO? zU#I^Qa?fgx0JC*f&qBUuu-B7rj)OZ9jMq4BZo5JFJT@*csCz(qxgw* z1EE7!l~-D%J=6?y-r-+J0eu)IPJf=cryiSaf66zhHepz>p_*;v0B##sTn($JN6Pl$ zlpDVXuz1NeS6w+D*{ar<9*2z(xeW1*)crjeF8yOGnWq^z!+F-VK9{1L$AT@rNFz#` zWC~xpA&CCc;YSW#r~=F9LfnOad%&X7sWsqwJH9v9vu3|j0N0oDXbpr0VfBx;dH2I~ z;0TL3d!Ww__8-i8_3T9kO8=%|Vb1peFPAEtIv*mxcK2o0q>d0Y?CyQP92|wYE%~#( z50a6!z?$G7#KCTiUAe#!jC~(;T2l%x1J~)ez;I%Z__h6M(JJ9@vg+&-oqcVGS{{ZL zj}`7f`__MQ6CeD5aT}XKq?HaVr!n{p#il@2O?^Wb;Y-`|S4&+zHyk)364IXhAh?1* zs=UQCBH%A?W7F|vE1VI(cJk84G+K_99whn z?H?YEi^r0%AaBxX*Ck_IKD4taX3#j3y(}r?NP#$zM}uF zZR9|=o7T!^lN+!!+O0{ar-R3#->)*RhCtw8!_q^EOziBW(fV2y1I+P`|pv z|(OUzKn+_>_ah$~Li)92qUx`d@6E@DBl@_1=V|FgbYJXj4>dW9vZ zL8-nH^>yZ#pzY2kptKZ$UG1mdUPwxZn*q0uzMhPN1MfY>Ev|)u?3eD85rrJ@sm^vIYpyLBJnI+rR?!@8e zy{w(MdhivU;Vkn2 zmP(#lo*Zq)mG)uxgj2OZS-Ac0VreJtDD9QYQj$dfIX9;2ell*-b>F_$IE8~Nkp(R~ z3!%D)UN9=69c&-WtCtyjLSV~MNzlb!OtmbQYIraTyjs(vc+3h+gOx~rn;saEZL*l# zTghs*W@GzwH5 zDdE>duZ@Gl{iIBMAGoHQ!RH2*8W$S&91evvX*c7RDF;-nzb#I;b&FtDkj-3qASnAG7x|F zIW?hXAx~F&VLzmdNbeJg8blQqv%59(ZKxp_%F6aV0Zp%ENVL^g;!};fj~wG2Fk~bU zx1E^l_353tEESaw8iU7Pn?ETea_`bVtF{rk2ZozRznJ#pp0J^&T-{gjg~!6tk?Z!z8>FAmG6NGN?eVF z+ZxfR|7`uLSSFDZIeaJMxCbQ8ihMXO`5Gk(=oPKbdw|uIxtv~#VAMKhmU;SV6@Im~ zm|<0pfDi5sGVgdQQ1Sxx82Qfz>6`BqIn1XR79Sqf?#yXIpNyZ}oYszz9B-=pvQ8E! zX`-5ho+{wP$fIVf@*7~hMOI?e^o4p|jl(_9-)8V-epeDOkAKCnr$Pw7`N0>(#Gb{4#O zc#WI>)`N+3lsrAp6g^piy78T_^lx_}*FnMBKO@1|r7zSz6Z;aVtPd!4coc%xoNP~~ zR4V9EzI{?^5&+Hy`}`@|qk)E+QFqSQ>erDiV3g-;#ZdO$ty%F(k*&y9gx4 z-=%e%P~g(~mi&F@p&UOgxDxTi=c*YpNy zy8N8Xy*pu~?{fc7i$T=WINaK_tq)A8jZ$WGYGKCz`Dm1G7L>EfaIlRhgRV5Ctq$20 zWCtWa%FDLNCN|zZ6SNZULiwDL-``e-ujRHC!IH zfQ-J)pXU*B->N*Xs>HY7 zUUqKvONYOQROIQ>6aV>s%wW+HA2{QIedBGcw;R&Y_sL`PpCgLUx8GuZyPhvNoTRcX zUMt6|TWI8;TV1LElZ^2PW$Ja%eMZ8?zOW1OhUXvfIkdpL z_8iyyCx$R9@7z>7_8{-~Esqy-*_e^r#alGc4p#qt+q|vy8imNoEoSX4Fj@EKS=G=> ze5chfR`Vhfi^Mm6bO?>Z=_9|`j$ch7bWdNHe8qj?UY$m&q(LI&coi_!fi=g&+x87FhzrAM`B~Yln&xs<|TO9ACFPy3{(~sO@!Zm z-gXD!8%kOhFm~dv1<|IEA1|HykhN}qw?^&&Fm)djWXY}p-^RUHeWsHkTWm+?$C3&t zzp?hRK{FZ6K2%+Cpo+nRueV$cJ^SEI#Az0s;`Ff1Rf6S;y$MvWcQDoN3Wal&-)%dT5`kTLB;Mw<6E2)RwJqd?H`47J zT&Hr6g4bOZB6%5Buq|xRFI71lO_@GdZ(lV7$uTG?OVr;bSzdMGHcC~WjeU9I z4#x7?R^=xLAWNRduG6vF_`po-<5R-_C3eN<&a_+vboLeN{Ct!HC3ew6-**P!v}ZuXe47TZ+n-7$X(j*j`L$#udF0WYB@DZAzR6+Nf-@bD-k%e- zf>2ZXy`8&4VB`3a-Sx}Kc%~zrws7JJSXCz+yuXwJf8)P1I#4KMtD%1^gYzAvkyub= zxKH#=NhT^bJM7`Bh}3u&djX!(pAcu+l>(;xfrt32(oyv3%Co+W6g+73+}Sld4b;c{ znpWeU0rwTBf&vy|f5!CpJdDNzdGYNz&xjCs`OxjvlZ$EK!u`mq;E@lCG-lq3U{Qf# z2N4=Ndq;fVbcD%BEDW>;c9?p<4Zxjelk1lVeSYN`e{41@A^ZYJlTm?uPVB_ z4@|+9yV$MG?gn(F(Q(-#xGB!R`edl?lR=2wlf66HHT!)1*f`i%Rs0AiH2 z&XPJHdE!E-N3$*5na(s<9CHWW!s&hx6O4AWdSGCiQgq(t1|DCcb5&rl7{sJ4*WD7&sXkH2~CDq`a`*) z3NfhM)YAHgoCjB*ok+c5ScHlhnkUz5YO%U%o-^xm8AP%a@0HT22lj!hJ5If;hQ6Sz z=Q^@=cv3oKL7;4}JYmV`4m^UHVlrco zk)2(;HNV0NZVh}-*}V7+-{^I((k)oR&(fni{7Yi7=6L3wBQ7@B|6tW)@FbDL&avRw zERl{64X%$F|d!juL%a)8p!BDKDUH-MAFoABP49VpiTpM&flcMH#z4p^H2= zSNrzq3k(xeXQ2I(2@USgXeqYzP%^@#lA}NyZ}|VdS$Ey+pYO-02S4?5r#&E3C2Y~l z(i>wn?(Y^4%7C(%gqaqZKz#1FSAD*_36y8dH6*ucv2Wm~dl#t$U)-R%r+f1;3aHo2 zhs(O5;0Gm^s6)B1%h`~JCcFT@>-?80d_M)ZvHhvmAaeea3xrgXE)#osa`WygIvdE` z)BVmg+yj0sP-wG0$%GQK)1?z4@j$=%iM5whhy`TL6F&t@FyUyPL~_ClIKI?z(3`Ui z9{%wtGl)KOX-nB343Z1NLB!+` z^WWx{C=WNG#>;-cTPj6(IYIlpdR!cS9o=57uaFC`w$r`1@GcWeT*6)Vea-=?!-+?C zA5BLOz1uJEFDF3fyZdtQgFRt_sjX*u*%Xo*U(_=$IU>z58HDxVO^R@48ORSPbvxHr^oR&D>lA3&Mi(kTJ%b%Axit>SGjnqNvDncpI zn)~%<3h>)?-nR>c4n=JLqMMC*GKL;W+~&(34QK7bPIYPnCM(Y{Gkp(5(=f@0?D9F_ zEcDp-(b)v(aR{*Gow@3^fzilSaiDfCCme1a5M6$&7==O|Kfg?!2?VQMMJXSvU%}oo{@p#;e9Wx(dDt&1XqhTQk7;;i_t|w*VTGW6^&pJ zH)v2ir|tzOzpv$;Cv=hKzpPiC`-(AmpVVs4dv~aoxGAlmZ$#v}-5h8eQu*ipOP9HZ z+Obgr<|Z#4Uk+q|W-Y#uu6sTNZ``@mXh|0u?JJkVoiK*T?#xdPipDv2C*#Ce3e772YUnO_J>E6V0KmA z?mFgVSgSL?v|G{-h0{a+KBIXF&!X+O#UJ&A4}C{pezUrcw^W3f1X^QZlIU**T^!); z8FAr#pIjjPi&l~`DGWYL4y-YYxTEBtYLWc{kq0vuo!Dg&gNK(I6^=?KLpjHV(pbR| z97-Ndpp4P;8bcQl!J`kt^?&95+&I@NUAMZ^MLU8^x7%gF(kjzmL|za>K3;EPL8j-1@up#ZtT*{RIi<286N1g zE9MdC{~Dko>iFMPO6DB1dbOhTT`?IWjjhVRrLiMth(SSmiyL7gtUOQ%;5*1^(CZ%Hbc+c2fR3 z-{k0{W_sJ?5cD0}`P{);4WAln=H&$HgAT*#%137`zyAI{V^7t%w33MTGcFqQZKcD#?xc`SlXQ$<(^Yym91d&G%W2+Lhv2LUS30wGF7ACB zE!lbA9`x?bQXOi}#gWtj+Z$@eFt>Sj+T*wr+|y;sOeXr;xw@Z~monn9+s%eE*E<+l zR25SNmvm82q}Z)`w*w4n(WebAMx%s61zpK}5;7K7F{U5M#JdC6vK(7Ip!KdmP61UY z-Y$KXXQdnr9b&J#zuxP>71MooM$=_LTgRFwaH|sP=On(E4CbKh?HqM}jb3;$dasRj zr4bJ%%KZ|Q?*I>vvA=dqt>9>NiMA-5jO>aAUvt|9(3)=Un?ZC3(gj)EAJ{(yKeMa# z69Q}TKdI2V5qtwV(xR$@RXylAZ#dpYJBkmam^aI4EwIolvi#>EKQxvfRwECZ@T<{w+j4W8=6!)yFtAq7imy$RBHjyCy0^ogwB|onmcp9F9&}AALgj zi~n&vK{48+68F3&9R5noEj9%@g1?d9vetb!%-dn@{zKdi(Pa08T2B>j<-M0V^|=<` zB)K)NFJ|B%_iWV2l}XfDe8sexPU!w7lYf+^A?&?X>!&bU4L3YbUe>nEfxY^6u7zs8 zFe7w4N1-Abt62La_Y`-c<843JzWu$(cKc)G?yyF@W>nRjOw7R_9X1XX-{{2>%kSHM z-OI%(iHikdj-~M9*WmVJXA1G2-KC9C-Clh4=u_NBtu8zmVAB%udH~;1r0fvdS%L~x zt?j+05MKIuwV0k2qNE@(93aZq0_j%DRxudS`Y?)dmW;myUT&7Gd9x z3*VF(B0={|=E*Z=&tZ_K(i^pX;k&{c}(Zr!!vh?{WMRm7(y4<0cG4=C+ zzsHUzaBt*bPp)j*b>SG?_>W4V=5a9m{GNE}H*+5Bi$9S4>%mJD;-@h?-W3Av+!eQ} zHeaH}lQd3)?TNV7yk4ew#|7=?o<7JW{Nn?Mb4HT{C*Zlc<$=S5e$XaCQO@~d2S%+$ zoA6R~!p(Z_tF5*DkUr$RKh&TV!|oJYyg1tpz5y#W(Jv!0KlkEm-7|T(-tRuRG}M87 zCdQ-FgwMU(K>2RYqk1?NVkzxFd{=WNZHvFR+KUG+OUcHmyoF#54<9bpV2E#tFv3?~H`4 zZ7^ECfBO7moe}aL>npiR9fFU7gbxH+h2vN}*Wdl^e(<1FXL;XrK2ll#t@LGThL`${ zRIaKoL5GigE~eN51K6)VY*^1G@@%%GH#}U>BsXk9?nE(c#qfT%dgBUI9}O>uY$LdZ z`gAReFI*r$TKnsf*U$gC{|d^SFVSKmI9|tfm)O3l!S|y~SDDfcQ2u;9sVm6?X-yNVoMS}h!18hJzfldxXStVu-3upwC5_CpFMDI zln;%Z;0SK$R*7!!835HtfoohA6%e;f{V)%b#RSKNq@DcOVhtzLhl%X$_-7VE1sn*D$O|@LXFa<_2nS8qOK* zE`@AsiOEf!Ok{kXtoD0L9$Pw{@&YvmK}{;fM+7*u@vTe(~~f(@0$f!Z{j`*~k`2GTHl zcJ?ekv5!d?aPAtDPlp%_0x~aufnmj@I%P$ae_~$(lxhaR0Y4a!kBj@+d$q+>Q{69_aRdH<8`h^ z;^(-l6|G|_AQ_;!_nEgBURj*0b5FKL+Zz>Uu1>@P;}YF>kqfrq^C8Ll-MBue@Mfg3 zT+{)@t4X=FmQCOw*FPY_4O z@K;xKqThfv%eGfHv@5|Zoo#z!N*}Jb^d@`|O+)kGiFv_;`B*;McH~TP7fLn3C}%+f z?)z#;^KqpgzWZzvY z={S~re`?X_1FCA!26{)NL9S)gp0Tt_A_rWz*WyVccpl?UGq!GrldFGAs^@FLDtvF& zCxuKH_2t+5Ia`FPnVm`8=ifjUb3B<9hQX4aXa* zj`G753C~UOhy$;g9;X(*_q^5Q&TR%i!n|^4&<%9f1l@Mb7~;+UNJ>W>JdsXj?!3;X zJ%r9>U(l4$!}T50eL*UkuyHhVt|{R$D9e!Y+S;#x6m^uhyonL?ch3CybIbffXbFtnighTsA=%)TP zP|;?HB|3`|;&v(EbH41HVEf~Lz8{OLw~eVT1(SQ`pWj-syGJ&JpcTO!4LEqcQ!Or% z8=53+7pY}EF!hgFR-Z#5h+Il`HJ72qbBgBWo1;P?>U>};tCG-*{TGmWhnNdUbW1g* zE{mi1##h&-gR)q0rbzc!2MhYDu)n6#{7EXkYWYdeJQqJzs#q5`c*9hRW&8mrF0_dW z9J3!=Bt1xy*Gjxvgp6tuyZpwjL5qilHAjj9#Sg5K50`%?t7baAE!`ObjvBk116iEl ztDbQmr!u#U};8?nVNiKQ*2hxMG5pt`7?2)-h8I8U2@ zPNq%c1>L=gKQ5es(kqVZeoDG%KK}ILYnxWIY-~ntG+OOZ0x>td?xCD zD(CMC{XnuOwJNNy_mf9oXdct}n2Pkny2(%P#e#=JW5*B07sNh>Cf@ZxJp9dl`pvce zIPR(LsUXLQVn_0WV%{T>IQ{-p7hPH-tk_rQzxpFUyhpAr+XK}=;cK!0W8zK}r7JX{ z*-ecD{8}e2nxsNU=-s0AV+ruvcZTU^1r;uao12^WA4F|0ZpyfyzC`Tye2eV4WZ*8T zJodCNmtH`p^Yv*V`MIplgx8Mj%%iPG|o4nb)x_&#fp?>tQv z%18d%P?S0>Ov8bQLhEH1(oXX|EQi{3xxs@oIWyzzU!i|0$W$PT29I(~5eKlQ( z4Cyh~f}8%9BfW8FaV`Tt#L;eF89yq4E`!+@1wvn=ZQA%P!I$musLA+JV|Wpc-HY=w zeqINM9>{o$oj-yiR@=UY?&Sr)>>k>b-g-Rj&(NG=^#;s)$4$}~Y}RuiUpIhdM7tg>cbCTO7&gIQ zw;P)pHrzprnJaWN*^hjOf%B?hV*}~Wson0+RTQB(Qohs%y)l=TJ*kt&9m#q>_BNAK zz@+y5=+;3ZuWBTpjGX8kMIZNpCEw+X72MDD>vawCSs^fXMsmZ-v=j%l{bbZ43 zb_3szGK z&=~N5*03!flIKo@WH8fW%|42O^wS6M)`VX!mr)2xGS{3hu205~j23@RGws5zXyKx= zJPx@3JamVFdkS0(9yqo!T7i*<27*s?s4;XQ%aLMnFIHHFhH3AMfTn2{X}QEyFtwdx znB6mt*WP`d3(g3GdZkgh`_>9LOW&fTd5i)Sc$Z$uQ%n-R!-NPo*SDzgk@7#Y7=7IM zEy?vQNde7FvTS+2w8FqM_IS+&HA3&)^O7s{I!G*x2L~99k~qdRtFnt4fZpI7TkLQ? z=u4-LsuB0wpNLznhlt#xj_&WW-yc_y`@Gq6E|;g0{+w_Z@C$JUj-_$Ub;rlZvEXEE zc%d3Ejj?e)sL4lhI8MGqa}Pcq`Szsy#0?OC#r22gTQ{VVZ!xw+KZZ$n@es-<`e1L- z;ugn93E#xZgkF7M#JP|L)skR3ko>!C8Kx=k;5*RPh4CJddjdg9N4My$PZ?TQd|>EGVDOS1^i zZ8rSWNhw4hxyirmyNyxZWa{_*iboKTy7OkpyDpsYP_6N`YXl1D84kGn2{<-_F;?z>k|_tRg)yMaw`T2aDZXXhxEs~T-B8%iLZ$cQ~h$Did+uB%2kUp~0 z@TRIfh7$EsYDbBVMIS%ttg&Jri+>Isp(BVrs;@-;SOTmkmN@t?(%?p9E%6`Zgcrvi zZntuB16hw9cf53bFCXPu4<( z*yqLP9kh{EKBscxYdpr~q<@oVPR34sMtAXNH=(ayEbBY!V$g!r)}=^K5-Bd0Ma3-J$Y*1()i03h(5j60QH zp7NjT>rf0ism;(HN>J^Yznd>yQ)F#Ryp>PN-+AxvOxs>TXD>KUJ-R6QTMFkl|Lf0k>%(~k25MT9J}9{~ z-%o14f^P$ozMQVP0=9!>=e^(eA|Lf$^4@j#9*F~4u+rzt9L!mOdYdBQ1BZFA zsKAXxo56`Tg5!y^!fCKrVIenVPJAz`zn6LU=`ci}e_SoDa{^-zG1TSD#Nk=@^%9E0 zG#K^X=sldLjvl%^_Hsfu(LlFhRq}f@+J$)xzw+_Mhrv1VQ7>YlMI!Yj_nIEQXmn`V zadd#RrsXHb7@AC$oac0p*gZ>XcyQKs;J-iQKG9AIHFG%-UJT#c(eVh|9{Ot29_2!@ z%ESh~O%50kS@TVF3j#~Kje{9!J~-~u^2Pi|DUhqm9n~(xVXKauHOIT7aGvqN1M}kT zc=F0X*&fwW;#|w-(Je{^*{~&#!|D96Gqq@DyzD3hHHVRXOH+`)#jsQCbP1{--J?uC z#)NEq>ucMyIsW;6y#Dsiod-diWKGGSAB~+F81KAzEKzCo5-B4;_3>sfIq0coD;xD5 zTvR@CoTpw0;F92rgmd1|wAlLD_I4pUo!iErWh@8XjB^Xs*NJ{vYv*1eu9pOter$Ny zIU1>Hg*pCXjfOUBQ=3yt*+}VGrlH$Sg>_#)-s;<61_tARBjxWh@V|)MH+quUz&x%+ zF>r2RHy=srG|B>}G*(f2=?pOMA<9RZlB;D1?01+%;bn`#9d;o2J2;?7^ehWOQv~NoJ z3LyKe+yfixd+30SH{!FlL2yd;sea#H2r&$8+O_Q&%J~H7^AkB65B7gq4Ip#{%!_rC zk6L8!Q4liq?Xj!zp-`Yu&ZYv#aEMzqN{r6if&2UK)-^%%nv!xrq$qw#KdMANC;}Vv&zBpH3BVz(Qbxm=4f3|r zbD?J*G~n?Xu1Id-U~nL>rbtLCVx6GzeXmVnknKHSs#8Ju(>I+EeBVM0VlY(VC{@m0}PJuwjW`42#o)9tr zp4X2}7oTiTwRms+h14OeW*u;*lRTLAded4-8+C7MzqUY2_*DFU$(QQ``9b?Fp%*oa zq#?KA$c!UOP#`trMDa`+%WwHH-wbIaDZ0%us0}pzGrv&iynism)jR0aK)sYWa}18p zggzS|cPAH}>=9n|zC~jDvVMnNR~cs8d$-r`UnlFotPEGG%sbjFF? zgx|j<{^)0_K=<&LS^Bm@I8jZVu(Cz?H7@S?9%-A4Qa>u8+>zi4ik`Y>)yD$ESHC?N z8r}iV7;5jT(h>Zb?>nOo9ZJDDYQv-z-W{MyGtH-&b^y{oJbl;GR)OcvY{Va&NC8pR zwJUiE99VZUEN5HlE+E{?<%&7!a685Ar<2eNkmzCk9{iUX)a@mi8=kL{gf#rjhq^Cd zN!O7V`p<8Jl*0#^+)G`M?L2*@B7)H8R0!X~&Iz(jD*gO@W?~;#tnpQG`5`EonT5v) zOo0INaAI?&6#Na?UKv|`9!TA9_-xmjFx%6=X6L?2JP=ZPdxwl2E^aEVo)2<|Z<9Jx zH;$L1X-#X-Vd{G5e3o$Zy0kN#B|m$w^XUonS{Ltb7N{U;@>018H>Qy|p8c^?^i@TM zT8iDPCL%!Up||Q1sl`MGYw0bQ7) z{!3~sFz0N^rNH53mdTkeV@Q9^=umOM3Y{Dcj}`CwKw=12rWR_qY|0ti6-{>F@H32Yof3%L*ZmkR~c-VQ%)AJNyV!tzx%8#T>wy*iZo~A zLRy}p`j6ff5HPjf%S5FY*#9zD?0K$)CU?Fy#`~Kgd@1tbL%SI4P+Qx z|>L-6!}xoB9kY6Jb}$G6%C zIidTt?lfce3@Q3tT8E{WFQS0Gn?-*bbR8kfboA39XxMk12dROZJlcTvTN*kN505?in8>@;T;(7H+W4 zkk4#a>=PAc#|xrLs*FV5IfoRTv}fTKSu>}bD*Iq0_9k|4j(m-PXL|1QPnq}Q)v3;o zZ<&+Y?bZt^Pb)=NjVg`n}DHt~NdGj@$;y?Fa zXBn5iKRQ}V()%u2`ZKGD#CKYnN#ec_MoS00+E4JrCpjdHFL+l%RilM(kWe|=d=zq^ z5|n^rjyFVT4a6{Y&Rs`pwh3LHHVupNrNfo8uR=?=>%hw`mLsdge4?1z3>Ocz9k~qU z?^P72uS(&~h7UCbHT&QU?`J9x)=`ix)w>q%l7rioK7{yvx(G7i*Pn1tTtoVVUrsMf z-lDio?YOenAjE&G=w*Ld45JsfCN%y;VtUiNv}@as!S78&?XC~ou)&|ym-{*dCgabS z?<&ZG8IH-SkJnkiwwyk#tdbv!B0?^F{bhkN^rQZqLs|G_GL6l&{2SThm<;n{CvG$} zB29m%_CY^B2~DN`XdoY(`O4jJ6E;WpK9%!Q$7^9fytdO1kdSq1@aw~LQc2?RItIe$ zp>|xF9L2+edit;hQZV*sg=N&F+^vJ~WZ8P#()wSlJ>aZI#+F|Mf@Hy8Z$m zYkw@vEee=X;l!vaK_QCO6WC{7rgHA?LEM+R+2^9V7dK}v4Mh+-oYbzF%WPUX&~ccG zZ?vBs_w2v$K}MbrGh!d!6j;arnrrK7><$EH;N#Gce8m{)W8*eojhGXVbnW#!g=;3L zJo@0W@0qfHt}of+Q@fs(yOJLZDDgGQIgm1S*Arum*S8m^e zD|^Z~zPw_DjW5p+%lcEpaFqRsDzV?D_pMw$_%|Aq6Q45v=3FBeD|?;^3g^UV8IHcR zS{LLZ1|-{C3h;e#B`@3l&m?Ys2^N#pNz&=+xFt_%N34sjtZ(+QL)qW5Kfb+Z1iR9c z88vlj&l=Xl8GUxi?wYgsi6P1ET^Jw8 zWKV~P4tL-L$K?R#=aq0`KcD{eVMPpBzaCTLehH!;k)5MgKVh*`fb(wqQRug8(v&RM z!t13w#`74|fMfWK&oa{l{w$>$nCa{VF}vMV-xJcn`+}ghqfI#S$cwl5t9~XKuPx`? z(ybv2a}K|~#+Q!}O``acS8FKAj6A3LeDBOU zqJ~vh+$Gw4kmi5gOcO{AE%rW+Y&ZAgj@QFG^!SK6&6svO-y8=8N#7_qzP^e4>=%(hsknnIzBn&6=k*PNduB`9}lyS>vO`Tdp}t zvRKR>(zlvE1)uM!X?QC2pzqFord&P-U=VJm_a^i%Li@=+9sPdTZQA86M;b#*Y7w^f z3=2$p(RHRI#sRpWPr3CQ@gbcaT)|ftkiWc2THdY>kK*4)vw0mT`c7YanSmEr(yiN% z?RZBHg)6E1!%88G>k_T5(L;1K`#`?=n+qmLrolfZIH1Io$UP(MriPi6p zJYto+1YIAC+B{A6Aq_u;`gmIha!>>Ywjp8X#A5l}_>o&xw)`!fC z6;-4Qr)?A%t`?Bq(Q|iq+;Txu*T~S|Z7WngQO+H9Eg3C;S0&w`2?eL8JA#)~#X+X% z7H^oW0RCW}qBG0RMS0iz3>98Q5HD+`BvE<=?T*{mhX`GV^~>BTSIS#RWn{%08JrXt z9J6HGa6uC{Us;#%s76A2xZqXeoF$UP%lft3EfnaK?s@)?juqC7OP=~T?g_F_ru5gZ z^phKcLS^Z?qDXQJBcFQ*b)Zb)?#hE+?tebNT+Q}6v}~G@>rb5t(NEDLZJrYx<5(4k zxa4bry7m0HyxXqvlNG_|Ry%vx!KWJz_tLt0FtT7pO2xL<(~3}etMYUoaoz@>==%J@@{t?^bo2Uw}S>(fIzY)_Z%^fW4i_HV-Wrv?*{9Hd+M z>|-xkK%@Hd1Zj};r8N4d)X06D<&C;ieozbQ>PFUSksfy6>7lFO;efrZ^A}eq(onBw zOl{Y>3Y-(EYd@sF8*WZnP&Z~VfZfM1U%6j#_$8K0hMhABbJ>N3f0_>iOQeeB9?A*G zqz+{28kd6q{uue)n)lM$|v#Uz}73XcH$fvz2ib#V+yQAK4=QZai%%BH0cGou7g_!yJ*_f#byP zJ3;tUzTo`}y;ia!tFQ>`W)X>t!7FsWJrMA1fx4imEl#q9NPbGL!z~-X=*_t{6jm8> zRb5ttFuh8~oF?LXeLt(|*4Y3e7o9;a&9n$!79^&z*l{B5?>(w>^w){J*Y|B-4f@EO zVl(WOx4K9jXnJ|Y{t4K>+NwJ6O&9a&B6wu%7Rk2rrEQ-KM#yy14U$|zmeBG1F16g% zN5EC`34;1Rk(+PGyw$WBBiV=UGX9`u0sihnD;-z=J^#_?e(L;prZhtD&*q~<_(-p- zhN;u%yd%qe9yZX-Xd>HG98{-ydmhxrl6&0J&SI8OtZEEZDGKvH5{_!kgCU2KAeWKL z;Qm>KS1s^5rc4}Sd6k?7Q;)9|@P5uA_BT}OB6K5ge&(RQKdA?AaOhi{x4DL|Uwgk< z*(L#nPY!))IXeP^`Q*jc$!@f0UlL6v?kDA*Gu&o7ufdvFl5ooO1Oz?x3S<;2#*zM$ zb747hz|D8IuO#3wc1oWAJ$v{Ac+&{y9PaglI`8>``hc6Tjq{EF*V5mlg46kZF?;u8 z^+ae0?qh*1wU)k`mpQPX!R_Jhxm-MLeo<$45I^c)y4PxJ(oJ&k-`n@YFAJo_)hC!t zWl-;b+Rpo*3-|l~N=jvm3Q19sP)1f9AtNEOk}X?C_RPx4-em8+cR2R0jEu4(N;H(D zNPVB*zu@!3`}Xo9x92Y$*LAMzdYt>+OmOk|hjS=fJ6z>W!3ciB?IoVq@agCPhL|ZE8$xfSF-S7)+u?{ z*0|Uwc&pb5SgVz)RGt!iw;m=Gq_rF3lgx6B!``3T{B%MLIc9_K_ROhYhYa1&QO)K< z2cciltZ*Q?(z^OTpC2ntV$UiN_||gPVSUoyLXo3UH9K%4PdqkO)#iF}TbtEkn}kJg z3A}e=Je=vJ0N6b((Z3Y@45&QxP7L!`Bh`zi!}Pt55a-}hO__8IEaFzHjV31vd9U*| zV&%@zxaizIYBdIOd&E705#uOe^Y`>#AK){wDE{SH33$E!@q{AT43yE7kEx};M7pM~ zN~LO5bfCHLXzcY3NIJmqJ)>Y6cfD8H2kHml0W+7o0HqWPu3wknUf_cW=Tp;avjiWc zR0Z2VyH2#1Ze>Wkqlib8ZM;}(cyZ;wwP!vh)u2Q#u>t${ zzilhWgccoksld}BpG>-%6$A8hxX&JWLdfk_=2#kK5b_P*>Ap#y!%?#NQ|rr*qn*O6H8?*RPpF) zw081(-V@~L>V44i`DL2`OCHbMpYFCRa`xY5_EF={RR7L|rK89rciqNB+!2)v+pN6^ zzDR<0Ds;?bPyDIYb}|*mK|DnH(%Or#E~RAIYMxE91z)ej61{~E;G@3rQJC2eq7IRK z_qCf9Uy!!t6XjYHUnh#L7QI>k>q_?m81$MU+v;NtZO0i1^$0k}D#Q;fH)zRz-iktP zsWSoPe@lUWnnj=J-M_YZireO{tW5uN|21aZ{FKa85s0Z{o7olRVLD96yfxHEye4n) z-G@tF;+<@pPLB#$VB-o?|Hr%SZSkkKMT>`@VkN2CkHrX4a6Q=+$9h5oPfHv9yLN*M zG&W{8kKSy=yWR)OSqXj|tp?>(lV^F@k$W=y)6WP{Om0v%XrqC9tis3ID|gzibu(Kx zTI69bui5-*#ym(?8u%)kati#yEOtV_J@IAtCgi=b zlaTOd3CYhCX-#JbAT#YgizAe!Fn54~p5_6z?U=bexi7gQ?xcPGaQJ;me5A_oc!iY% zL!PbfdMxK5g}S+n-=}c2F#VOTa_Ao1_7|l;(uPh_^E=sw&Wb~=6XnT zDvb!-kT`hd0Cz##wTHcDnN2Oly-@2^jf^2gJdx=bZ#6<)wl92Q6SH_XcS)*EegUqt ze#xtEd4xgxe4~ONDj>8RKeS@Mh%e6mrncfH%&)J%V5N=gg$3bbVTaiJF^$>xriD8n zPRcr$1-;@2onsgOr3REkm5aON)zCsX@P}+W`ouZBLgc}n@sov+$LCG14{b$9OCGj| z1`XiLYq?`Sc^++y!zgyC&cgVg{YAfMp5uj;?%g8OIACXWY2^Cc+X|CX+E={TK)7?i1nt@r5PN1Bn)SO8jfl?~4{poDfe$zQZTN4)ubt0 zdwrW~_vHX?G%DCW-6sK?ee3yG$j@TUMgJBuiFRD$?hh7LBY2K9A}d%lW2%a}XDaIrJi7REE+!}YE6ZbxOy)}}|1^Cs5CO>Zn zfS-9M+jjOh@uM#{`{s`k0n6s0v&nv+HYp{9yda)nuQ= z3rrBrH*8a{!jDU|LU&B1k?d@(u)%3mt58GchG%I zc)9=%r|rx73A7UThvyf&;1BcIP@BLAunx)WJw{*MX8*5# zSo?CHxDu%tjDI!2n(AyT%P?cqILD#Z#@>x*qN%UXN%!HGx!YCLwz4=ZHJ=!mc^tew zUc42osf77QMlmCAeDHX?${oWgD>(Enr$eyJ5TCJ9npB;AC4R|~Pfs>zpv@rbr;~q& zJ+O3ywQ=a)N3NO|v_)d;;&%hf%vv}W+P0nTJXtsIApiB5E=vz*kRJakp%&iN#uLRq zq&2o8{=dFIrhIc`c6XR;v-q>@v-zc6yi$GPpJ`hT@M;%PUThD;!iiy;#n>9;`Fg}M zm#Y}Q^Gvu{Itn7Wyj--uJ`d0s3%}SDsRSRY+cno!%pm3FW)E4ABJTgm$tW&Df~@>n z_BTo-;o`;jM;1FJ!AteFwo2{<9R0~rIoB}(w6|TajkSmqI8RseliTlLx;@j&4$)qG zlE&~_EOr*9Dz12NR4PE24N>onz7ya+*Z6sPbrJoq3J#wltHc+xR1Xww6rf$o{qNNe zJb0Osk81w!8~ncPTlvui;TWU9ERA^@jv9znY0y=nUfk`}ZWdDPKQG6ury$)>bW>i0vPq*gT;Zd5r^b91F_rt$8*hgEOI z#hfip=bb18L3gDAPojJr@_QmAIqU=(J<3TXgn9OW_Mi)Ym1!`o$N9L)%`^DXSLAeb zgF95zyYz4k`64Ze%jI9KG>|v_{;Tn?6WFt5W48QfwQa4}LMQ0-8}aAQMsMGj_XVjn zn0kKVAr^+ngy_$FYg;Adc2Rrsv27?qT;-sg3vgbtyEtt zyY%%UnsHR*RyjvX4Rqv-YZQ(E%I22I&3OsJx1Q5?O!9|uAZEhi%-|?Uvuw4`QCdRi zMIH3xwnO#zxvE4Uh%x1|dTK|d@$}3v_3LkgnBC3qswh5%lfyL`@2n-j+w~Qb{b4n@ z+o{|s-$mfcExs1X{xb^>Gr7C=tWv;rk+QWniVw8xhw@)`5V*V{Z(?*+2wb}&WvZ_f zH(^Wmc9n#Y1de%DylKjLjVwbJ0ak1ykZRvQ?y6snMM%xZBt!63JnB23bDkMjU+fq& z8y>`8)D?Xa68bQ7s&)7qMHV>z5I(_D_fFjI`-#{gi*ul-nRKUvFbB5p&WGWM3xs(I zp}MaiCFjiU1O26(Wm!g7a4nA$dBL_1YmD;s z%L(_T!c)zY@ilhHtoB*q=(-{BhTp$QZgU8!XH6bhU-&J~nbSYXYPZ~`!e5;&P`c9g zzCe1r`<5r9yB(d8-|+%L9-Y%to=iZsV=KDv13!M7K1{Zhm5l=Xevb`EJ_Cg?vBOv1 z9|NMdfRHIuDDGYcq>O-#ZJQ zDw9*^hm^ozUBGt4Y&H6?e7__u5KHi{PPdcRCj&#T^4{g`WN?2OC~=;U(=4hmId@u& zz>^8v@2r7GwE#Idn zwcZuL+mlOQIaO-$6a+#-Fx1C{5ZMm8j?PXtx={Pe5Nxva@a@U!S!h@ zBW~cjKtz~JJbEOXQnwuqej2G2zRAQPt4C_n6nS_>EmrG?Z7=NG9;^8oISH5NGp=?y z_G0dzv+s}T4M2FUgYwqCcDRd%xShzX!uCfeEp~?#{VIC z?qYWbgx-*G&HZ!&1tstT)3msDh)ID&c{5hr$@CH^DmE(4oqx?Ujpw%3w?qXeaDPwg zMEbW8@c*|+aPmxHQYB+5P({s7uOzk!sZvdc(^m*{lc#ykZE19)Fs*Kd&xvfX2%@t0JeC6Y zGs7YF!~h;TxS7sK(}nEnjJ!v`HUZV1uxIDRY^+nZ%%%#>fd`^q-!G{9qNe4`JQ+JX zq}RJ4!(%NLC2>@0)?qhO=_TZyN`ezaR=cvL1x$d{|tXMIyOfwLL!eo}|{!g={2 zTSiqmSmX?L&s^pMV(~rm*91S)-B6{4-{ORGG-t{`@^x;=<2?6q&d&)H0uw%{?N5dc z_q-GZh6q%9uq(cW_kq%Bd4Cxp!LORFpEm5M1=g?WXxHhYfWdEdnJUW;W>3C!EPC$` z4wr3N`?@xV-EF@3)y1Hc*0Lsfg z!5m++psvWBTg%h~m$W}zl-Wn%sBCP@eff}uPPV+0Y3F?KrlmFePOTr-Xb&8cvnYa! z&*rB$>I#AM(eH2Bmm0wCQ!Sl)XB7mCZzg%=SL0y*-MeYV$w;R4Ayl?L0hUv81h{z& zFkY1M^sgKB7*N&1`9gr;o3jx%ZyHMgN?k7#X4+_I3}F}1wM>J`6{Ux5Ju)zT_j!sT zUk*qSH`<bCD!M#6ntis+bs zu)zZuQ5X;M7n8sj)}Ge&tLj*rZ+eBqeq0m&zdH~ahZpP>S0?Herqju zJDpGfmaX|x`=Xj)IW*?WTtgoy?|y2tXnX;*Ul{Y0DvL4rltzUda|wQPWUVf3XhIX8 zi~E+TJJ3i`(I?EXE|P^Fu@O8%E@|`A~6)_|<*- z7@(D#nfiFa2F}^?#O;mw5aw5u_wCw}fvvEF1m&U%yo}M@f6G4@8)iZjDTtGh(q*J) zCD;H$uDgW~R9nEvRh?MkH%73RVZM}A;)wTc|2k6m8$k$7=wha?8@O4=GL6~RAQ6Xt z=TGw-2z_Sn<}eKeFFEg>HYHzz_lU0Xrtd|9FDpjuq@g#)cC9@h+qOfI9*d4|ZTAr- z85Nnk{ea7e`{L`51WpzCcT<4{Q}|VB6mWaS{Xeg-_3dUZxBUbjrI?14>emq%dGzzD zqiPd8x1m!N)_D$B|CHs~xDBH4idm=jiz0kDp8G6OtrAQV#Jepe7BRzp-|X?z?Qkop zPK_+B5mh)I9+;f1CFJTwf}RW4fURZOmzX<; zn#R&G?DIfb8G91J&ylD7-a{4CBuxwZtfTNvSi|1;jdV=wUF@GBZ~z#tk*@|1UV~*3 zu|w55T5!~%P2v>0A7;!a84p|AgP8kvlhrjtoPUz-Kvu;I+S2bI)NWQl>3IB1z}rlm z86a=iN9l`iX1tC|i(5n4^8>G{y@O!v_*zc>UJQtbJ^IVP{ur+6jwZ}pl7aC{yQ!a~ z3*ecc2Z=~~67G*?y2K)$0M-wZDI5LxF|LULq*Ps7*Pt(FJk_aq=Rj<*r96M!Ze(mkWgF@6q#g1?(de)Ox$X>_>iYYr+ z*I5djl^+E}+8{Y1 znEUwUOlWxXXm;&N6z;kR@%4pvK*QM63O4g*4B-AJz}lG(6U=9iU9IzgThB`##QrQN z_-Qv+$a<>aYh{ME?14@go=D3%(N>H)9}j$;)Tlycj@|PTQ#qih|L;VMLmh#8&qYP@ zbRITS{)+P_)S^bjFJh-qok3T&M!T{M|z0qEXo2bb^GQsuL%6+`_~@O3 zcUJcL>yek&`;zG;Q*=Jc&U|}H6~3uH{CHX25hl-Xw}t6GfwvsTuF&u35IB{#Znw1b z(8=KRiGL%`*c-xk^Hg#GY;j%tAfxRJ$6sHU?7m=xbi^dG8MmUKoWxX=n8O7;PX<1z zeS06-CNq!KjA(&mTYj9ks{{H)I$TwfaKXO9W1`Y$%uwEFU%ubVXvk0F8Wx<6gg4wm z^%T5$n9wr#SLvN4w)oD-_-lv2$#EV}LndROanm}kte*6r*O%d{EF-61KC-8t(3EXX z0=Z>v{sX>wxH4rd$a>`|B&wR3Zv9EX!Y>OBb~-Ugd+>cDXKgN;G#6U0Kdb^eCbk;Q zU4oY-Oq%8K!wJ}EHM(xwGYB4MS}acqKF8dU{qu9G)nG#F)9rd{n|`q#jRO{Eqjq*CNMWG6t&ap@vo{TRfp3pY8ER^#Z)`?^IxdZ8+} zN9vwwK9G&sZWc_m;4#G-rG1yWvGK+5Wl5oa5J-8+`;Ktm6?1REUAHF_yrWDfh6!Gc zl*fbY(p}jwRcPgWX&@QLq(ZYV*Ei#338*+;s0zBMM#41NiF&n{8D10mql4c^WR4*ZM(JB7BBbl#?csJ`5sOZAKO|1IBh>^))dXzxRpdZ-E@aBoTn;!G&oJ9p zI|I%8I@ZJa(GXCt*2wi(4lc~yw6%Z7i&y;)i5~AV#nZ(x0ujaOv<^ z+MFQ*NFMf8dWvP0%xSUz5+VB5#IbzBJ4mDfuiBm6Dp<4MlfwUfms!>#5o@qcge=GI?)I9^0AQrb79=>|IY_eeQ3{`uLV4O zzbu|P2Yb88%H9cPqiB-akIy|JP#v-*;^31CmsfwrmR|G1$1%@uuv1LI718*UyxIg_ zipBnzZSN|WD`VK~KA%CD2ewK-+gt)a?+g@-zH7vMs~;UvUftN4>qbGHIszw-sH`3*BOTm`d$6J28kw{|tGBe|u2Jn(cZH*)gz@N#ZzB-2tz^tR?;KgT8knXrO`RbTG z#-1CM(cWkr{%)|Q`92$EdN?mqJ`TZOYay%6$5V*E zEgi;o1TX&UOu*joPd}3E2;7_}rRKT8Sp=TY-7m2h{`>yxfs|x!ZpAdZn3r(s<#ZuG zzeT#J;53|=pxh;$X$Q98*IyY6C$L;Wq9RVY9b*oehl_nI!XKHPwi>L>a8mEz7W1=G z44;p9e)d*0sGZfU-_U4B0TM~|3;C_kNbx$NJg5`Z)|6Wgl8=Jp@#9Mel+)q7rj6JV z(=&7}HK;J#s|L+{e{$1vUAQdd-Y{{EkYnercsLnd0oMblm{iqcVE<(&_VP*j_;CFb#vFntp{$y}v;jT| z3=?(MWdkWIe~fZ#Hkjv^QRFs80o8{Vn-`aWcL=!V{(CIck%%(lx;y*r-62K8uIxLZ zU%UO8GA~Ns0bZn(MQ}VbLngYcCu@cTzS1z00u_-rY={2#&iP)17dx(9_-$Q2Iq9_z#( z#H9NLgo}`z_(>RxTpQYL2fRH{LEt>Ty`Z*_J# z27XxFETnQV(;PWYIZ%}j=YybSI(glPc;H_;I54jji3xt!qG$0jNR(8( zxb{37{HgCH86%0ZAvCDqg7mk6ah>)(l1Jb_NRfm>;)5KoqK${H_3 zBTq5U1-IWukg46)ulrXG_`dk|Ygk6ZXe3$2Jee;1ul@V~^?8e^9(B%hMM!6{Z2IG8 zCgwlR3A}1k3KJ0wO$)CxK<$0?r}w9dKu6!EkzuR^nK+xhRzq^Ib8?{hTUsR6xj5e1 zcdG@Ks5;pyy7FOoygM%Q@gT$`4%7{7mB8oa^Y4jsYN0DmKY!7%3wWiwc3x)&qMjKI z4W7@!*B>7ZSQgb_&b=%%eZL}D4NE^9P2i&@&p)xCR?9&8qXob7zGTD8U%R8}Jk?O| zbWHu8dp7Ww#CO*EbwXhHRckGST5vSv-x7|>g0#?~pBfx7d@s=62JZGT3dqU2O!vLh2I?@DdrLl;LTQK@@6x!dp zZ|(Hm1HG>_+%~6H#}@~~q8WOvU};$QuO`8>T&(kZt3VghyT33t~@+Tb&e$(^`DBom zf_A zZ>j0hlNji~dZ9h<$33(jab{gC?nK*H6P+3ZP^gO{^MfZCx;0|iB)ve92=0RkwA<`Gc!)hPx87~D72P9~0;M`D$Q})9L#csG?Bqy&h+-!(Ci%H$0!3=Z|*B z|0qV2KEx>eSfpWDh$HJ(52lVLVWq|syJ3?!RQ4(i`SQ!-Ki?n2hqFocbv(vUG7B@! zgIVBG?!hqX=Rn|lCM0eg%tm^itx$1s!uPL)k=2d`f)j_gSG`m)WJ^EKoBBrZq-1$c ze4k6k@2d+`0(UAgAx~UP;%xzPnLVQ}Yi~v>;ezeKie!j$zjGiqi!cx6o|a7SrvsUD zB^NaF6HsR4Vu~4g3J4Q3?nQmBgQ&^P!OEproK6=mIx-TE4>LwcFB0;ciD9~h`2=66 zP>Zzg`#C>6&l0BHK9-GP>>++!*%dI$my{TPvjE?(IgMDej^g8A{jKM(zk<7@pZRp_ z>M@jKUx@d=G00%kSU>)C-|q-KqBTS#MmUc*r(a)c{e`wp=qn`g4=@pZn#(dZpr z^of5HIvJ3MTvdYCrF3h7M`b=b-7prlCkdT_Z5GJovF#|4x%FG&SY2if|Id=Ff5TBD$hYQi@(M?B9F)!^)@8Y;@Te7MRGKpNUs z3(qOcTf7GgV1?ns;hRNS(0L6H*uTmFp^|YbUV1@LtTQK)qprhq4>(WU3UY;nzR2Oq z8@Xt?Wn3;JlaAHL=v^fVJX(>nc&M1w4VnLxCN#UNV^A0OXw!LL)M$}xm2JtzVh$ru zsu^?mu4B}kwv!IDc@s>Zk41rBepZ#|Z&gsu612F?%!XrOTyHh^`@#L>KG!c4525}0 zyZigtwBa4c582BR8t~PQPGxtp0;7jVOu|btk;1R-p2+C{(3tUi6>8-Mr}lj%*$xgx z&qsHTr=N)fmI=|rV}Fw#6=zd7t zeSdmCVLx*|LMJIJ+7G#@5=*1>&G7Ga?Y&XQdJH!B-R&aK2TRF{pyWLcm#=sFZ?SYD z9rgMk328F~KVR@wyOj?d;c=%x?nrTAD9o3@ufJq@RZBQA1+EYi zJ;K{(>d4Cp)m<0#(_PRrp)Z1D|rcl%n z-jPXrp9PCLW(~~*{#NEb`WcCPW>ER`Z1?SnOpt26Eimx@0h+#9;QZC^1Dj`OSHG~S z!xynF8c*3PAZync|1cyN^kO8-8xJPos|1}Lt$KZ=dEj=S=AAi2JgDpcl&poC*YY^4 zi9GPG%}>hdG4EA0Q}D(_&lX}C6MGQg@*D-RXZg7KLt>u+fAEfPP{8RJX|xwy=Dm==tLZPfHZU%*@+hwTd>m zm6kB)@a<}Bn`0DK`0=fUM0KDZgF;}0b~AGJY9)DG&BV($j7?s2x`CeMNi#PB7kabs zYUub(6$ngpcZMA9M5S9i8|-t1c;wAl-?*Dqz#X=;eUdaEUiGM!aRjx)AI2}A_x{ZR zf3?n`gqf%CFI0?_fw~Tuj5drjv-=?8uiz8~btPser}bw?EnPq^Z6C%`d^qtAae zV~K5g(2V>vW(ra>r5y0X0nYacZ2ODxFPr+BfFF&lC>VvIuk2x~zhg@!`=xKW-Uxc+c||u$%)vF|i^>LJ4*luGtCwCS;kfA))9hfH zhvWq$b}9DGP*KTo>T!Dzoc!`>Hhe1-O9EOyy)^po?s< zs`7Y`FH9oR66<^3cn;jP{J}5o55iQ={^>}EYIv<={M`5QGt^bf-1oxu75p*3(5g(} z)>}6mq8&Ex0D*1Q8kbu&nAZ37uk_IgDDpTtFtaj-#E;@cB3i1k>&NuD^8Q|=a}MIY z)0qn&q<&CdyVeRlM?E(N)p}77tc~ul_F|{3tFCfS9v;X_HP~E>MZUexYnjU)AkO%p zw3jCn-@ZE&>u@0zO;>V-Y|cM}&waN4N`r&Zpd)jpsJj#5d}qq&gPk$Tq3-DC_Glpa zF2miiRS1&j*n$WR4mXC#`6U2YCLSbI-t+=V35w5zJ`u`c^2Sx|2mq&i4f)&}JdG%m-5V~ai zsDRBB3x2*k?Ya_x;_@d0-Z!gahghGi@yRH7)^$_OijbqeuCAlW`#Kia9|%ZhIz0t% zm8sO`7Q1d8HHja2dN!0uy4+SqI=!OHc(8?`9_4OYQ;Fmu0Kv5|OGi~P| zx0u=k$-|<}K}DG+rEnM3#5cUy%N6jG7Vi%WSpp9^biv%tIu@eOoM}&~H^si>H0FTNyI5^; zz1g%U9p#+Hy?*sMgWx{usG<@@@O`(H|LcZ52I(ANo}E_5{Q>1<(y5_XStYi=OhyfA zZnjN@uxLQ-&p!I})4uq*SN-c{NQIr~h#Z*6MkmgQ6aGq}P}?&d;Qqc2-sD)M%sx)V z{l_b`x}@S!?$nb*d|v{g^G)X#UnSv}GV`;PCnSOJ_xo?ZvWTYYzqq|b>BVZBlS&29 z7wdNX1R>|VR9yO|<$X2MNTuG2BU^->@E=i!-Z$cEM%&2g+6sL4IpHS|c%@=`oNBS3$3jAGS%z2XFF-RK^s|tVI4nDe)9Yd9bbxTh9^YaEbBrCo# zM02hQtA?ABy%y_`p7!~RE}B{7thXJ{)2sv~TceBN{S5w2 zP$cS=b%I~G)JYw#=WwKR-{o==!aZ5ed(K7iBIHolVdE>SfnPtrC`O+yhMUUGqjx)M zaaKWRbb)ZrcashxiXgl@_3T}?{7C*7vb>aPa!ntCy!t{!{d*r^yPnwfoS`f@?tW{RDEhr*us51i!6EvM zPF<2Tz~S+Ty8E&4kyey2J0Opgr1ATk$qdj|?ielEiW)2x$kdPj_6N@_i6kfPK#=DB zt+FCvkFth8YxM}ZSc=7+W$!0(_|5L<*>{%>k?5fE_|xMq7-KBTD4C*+qG24h|V923gk&;=Rz~Azs^2lHHV5cm{ z3Yk>%vH1eF$BA^ zIpVk4*UEQBb1-o*A*A?T4Boch6>3atggP(f3p9&_90)r!(FLag`yG0lJxg!6$_iSR z+F?lZtzPtpunm+xZR@bUK=7V6-*^zt7KMwIYXYmYJ*&(KkjSq^G2(xn*n%S z1zCj;uZZ@!#sQOz z4s&M3`@njxGsz<{eIO~RcstFmbSYuHOAXU0`mx;iikRYpOJ~Kh^ z6OWvKV>e9TfX~Ta3wn_cM|rG^g@x()$dcdJ&D+-zgO24h!=i;wb73o2O_h5OeztdK-96lCZ@^$jfhnMpGxxT*=!FLSK zNv}MEh?4Oemsy!N;}3jN@ejd{Va`v*UP$mD_Je&zEEY3!fYBzw!Wrr<812ueT7G z`hIAYkCj71tro*8+DRn-IkIE+EFP1?NIXs!b;49^WWwUncR1Xzv7N!80g8`q*U9FW zVZ^i8I}V8tQSr(`OQC%%DC8KceD@^0=W7zoSRHjB-e>DhJiW-{Sg+TY$W@kb!?Zx4?cNGQl37Mh?X+OJ0DuYz{p!8VUaEq@+p*g%L)7L zSN1LIl+Jj9XI*(R=9W9IX;QolC6NcI)L-ZIwbhZ2DyNEK&J_OF-IIMEbA;I?KQL?A zBVRaXgfB%m8dP~7!viLMui9iIjJW)3*xNE1bImW5)YydLJh`C+5SIU>m0H@m7%6c3 z^Us~_JA#PgDX!nwsxf3C84eKmztJz)3Wuad;ppY_7cUz$!^VK*IAci%Y;AB4MK?7= zzhV{Fu1^<8eUJU)#%u>2+d&OK!d~F4SkT^K;<+j3wX>||+^3X@l1km||)ihVhFkj&CJIV=M@{&}BF(C)_Q(!Os^d~x`Y zo=)fzRTwTUSWZ|btAkKON7iltBZT?tazT*~=nCtsGKdu5sOY*6VRj4bRP5AfAB3Z% z2#tpFuRG{}NmBaeYe_smAt51ietED@&; z$Ns#ddG&Frct?ch8K)D0TYS(gc&FGCT)Z4ZPkCj*=G8ckD}2!q>+@hNpYT3#x=uso z*2y5eex+OO?nDNdD7>K*-+PK{41BKFs|~^G=i6E-Do>cr*kS)t^uPN%zH4_*No3z9 z_~WLogh)FQ=8R8W96T+6M~4`G-mUTnTl)M>#qby`@OBUxdzKAZqJ0maK5&N8EcrS2 z8v%IA!zyw=O(k}d5>063MgUi)isI70Oyp`OHhfS}Pw+anNP17XV|V)2?JbiWG)j89 z-7=qxyq;2phT;hrGqvmM#$Ak()(0LGOQgfov;v#fs&*K*KX>t$X)M-D+xRM9BIMjXaBN3-TjmFt8&)y*=OHmiqVeU1H`L}d(?yTq(TJnVs6AI8i(Pc8ws&{|0R zW)pZ)uIfzn2|=};G^uCPTM(aq;q(4kGJMc~W*jy+jNAhTUtbE`g&#xqA9{}aq4(Lu z@-eelNS1Y*Iw{p3OG)gn_%3H*&KLD#c2k7ByY%t^#TzA@w+i}g@@@hnr}a9Hc;%rk z$Hojfn=+!hZsZwK7f{`ike2Q9ga>&i&Cf0P;7aR&m>ppsWvYMmX%jNgXnIjT?^`k~ zgeFHNpeO#V8=&=0sDsm;!O{$MRp70??G;4eTSfQ;I4Z_jqiXd0NK#!R95!|4(;>;k zBO&tISqhEtJgvb{_)R&S=D(43O)VC!nw$6ioGL?j$bIJ6HBT^IFc;Qr4*H+huQ9g2 zJqwaa&?mT}AgiN+REH)!?XDHUHRpl@v=P*>8hp-jFt-*}G`T(#6BXbhF|!3@LIT*f zz9SgVJix6-MQ=;J0ITND9lsK}fG0v#CswF?a5K{-m{_X^O4D<^f-ZFc(GNB5+hci1 zZ83HM-Ctn-cg^2U{*|D;K2)>mT7a{%Z%+G%w&5@nS!6>*4xTlqlsT^5j+codmwQi7 zfY7n9CYbhQezOw>I%v0!PLH6UY)HXjig?wAVd!q76#N)f4GkyQz7`n0#!or+2hLZIfy#R$%`m+Xc&8w2f7jd&Ek^EK zN7^t?e-HKwc83xA~78Wrp_H$@403ks$v5;p*V5P8csAMe?=r>!kST7UuVh3ukWj-~> z;LFu?)+xoXZO2YBr4oc~i4b~R)e&zy?!VKP6AIa(XWvYBS)ryU163orADR`g{4pft zDzkbH3lx*aftkKqwTV_La(r~`c+&6~KmL54D=}>kR&K2~JP169151~KoW6_w&-FE- z%PHT~=L^hpoW>ddIr4eeaKbT%I`vLGo*Ijd;fT=3 z(lTk)y0HK-kiS@cN3aLiP3KFOYU1&PCF8ilae|*>zBT2C&Jg%gPjvHqsYQWaL(1i} z=b$2g+wkMu98PZh;Q7Hbf(;u5Z#!8!FsZ56it^hyUTiz9oNzk>Zr*9}XTIHo*Pg_j z8eu7fRh0!1bBj!Pm>ii||FjKrewkP5T&@DLmA1T#ql1u{Vs~^dZ5F#@#;+avlZz|a z7o2(s`|tjxdBex&^YLD-PpwONJD%G2PvMctIIxvuZ9TnT4>TlDmnts-kIo(YOb+qD z%wR&cT3!QWU0s4h?<0UOvy#3~%NzaP(cBP{b4LwN+p&9htDy3=oK{7y11vYc4cu2N z1A*&rrElyv#~!zDp+wC=$W8t5&D!ByRDM3g*SHY@4=(K~TE-+{S1G^E5P>7*_mMGP zdB6+Ac6A!|mlFCD1O2_q6V>RIcGXMI${PDNMyO|J5`aQ0j(F$07cw^SaB@clKz6fa zOZqUuTfVJ8I!N&CsR>U7yxTe zI~D>))F9;ad*k#qPu!@CP_i`Khov3D4&smXkjvEI^Ya29lz!cCpt@B9re+@q6xJ&I z&-EqgaxV91gA-~xybbD=bVtT?gV4}G3%p~O?B`x=4|%*F-7;dd!S_l7(OEk)xTdSM zn7-$L?%RDAT`zf~Ma(~r>-mH^G+*jOU(-tX=-L!@Um*a(L);y|rB$PD^PP{cTk^0E z6oy*QI-{je+mrXswUEX~F_D?#3Sz<^s9CM5k>zLk;J3Ocym-u@Y{NMnS8Ym$j#6fV zrQhqtqrCaJ>&kN`B(n)6`RcDVmE=NuywODZOd3$uFJ>;8=YvG)^JM>Q6(oe>X?NyB z&>+w9MuJ8N(C}o?$ul{i=73{IPh0|c9%IzZGpj;2f7&Wd##9`4rRa=ZPJ(Re58o^f z=c8Xc!~RXPAvmyI5qD|zIkb@m_E;LV!!lK8=l`SazW=fO-~WMYC?TPukP4xa(xA|F zAQ@4zGBV5FE2GGcviDxuGkd!ZD;Y^536T{Qq9RFr&%Xb_=ZDwr?H};Nb>5!m^SnQf zk&s`CmlS3!ySV!xt~$WUSo#H?*hR~Jn+I;cnjZ@pkW5gQf)%0f~T!s5YDb;jn-T2v}N_5gLZ z$Gs@GB~^`<=!1CrqndXe6YxGGa{?_f_d(=?VSXA-8(xywOKa~@01NlU<*t5cg{bWg z5U|{c85@6-24p_K%P*~!{1sj3mt0qNs<{Ss&%N8|RQ&*+Vui|7dR?$yI==lZ2N@&x zZexd$7OWrbP&TU|`g7IqsyBQl=353o8dkkrhhfR;Z!ebQ0CnprD;Z*sP3r5QLycy+ z=(m@xshaB*REmJ^Y*0K(eC`a7=?eur@kst_G=^aE>E*tpt{A-e{n3sNj(U&}g5fhe zLSRxgx=zbJ8@K1tgi7sB1!a>@vA3_(qMHeAVm-erh=lmL@R<8U1gApAuZB9jHV4u& zLSz&$eeOAC)`;V$3hQP)>%m89F2YUnAw;%w&)s=>-@_k0#0MHu0vy3HJ4Q_^&k!>e zHLm@BnFe|rx>t4`O+(q;2RL@RWa2Bf{A6O36_nqNxvAS81GeK&)c88@o{@JC@b=~X%K1vnqf5#q)Zf{#ZZHbEb&(D{~YRPWu+n%68Th@9$#}2f+Tc(9E$jzvOkv+;>H0+pFJP&UefYr36@QOhzVw$S4d`s>St!mCdr+$PuGJkk z2F;$m2P{ulRw|RL}wGsTu_>S*X@3WBG_17{{E^r4Q{RnSNSMsqFDaY zaM&w<)DSxIbT;S_x^-Sw8KR9xns0s4xhIQJ+Dv&{cYO>Te{}t3Zc+$jjFr2lL|H&( zP4By^&*AVTUieKJl?Cj(r?Yp4GaTwzzbrZu^IM8d%e0^DDnYu5O?&Z$F_=Z#ty{SJ zv8OAp#Q14BNa$<2!FVSWkAA&7WY7h2if^la2aiI2{^=t|W@+g4cio*g;xX)pck#tb zuc21tg5=BAHtY`V`*{L7`dLeUOBF9=QZY*?V>bhhM_Wju~(a^Jd3+yiAbl)uYeBK9e4J*wB7k_4_4 zA5~ra%isl1RK)CM7Zf!+b%60q86FV`eiA2B4w0_bzb2B4V3|yPSWTxIFSu&eQ#aLM zlK8Q&>+}I2Oh?E0ZTk~Ac_C`&B^Nu?U#nkb@W=z93)_d~I#U1h^VRQc#UbSojr840 zTr+W5*qb!9+(+pRN_x9nN4271;@RHNfp8z7yVA2?RWu3;tVhQ-&lG~7XZX(8C}QrC z!Iy!91Dz-wOHo7DUW-uh&BX~D@UHh?9_F4=tm%w4{6^J|%q-Lw!}8C&Y{GCeTunrisNbjNaH(b3{{Sk3|K3yAtwga!UG@Tz zR+yy7I~rk`0%n_)R34!N5XkV8HOthCm{(b-Eu-23Ah>66bSVWI$dq*(w(FSeB+i%!X&e$B%lTV@uO8e!~S>oS!KMoK1qnxmPot4gtWo zg{UN_Hi4XK&9kLDjbRrnH|x}fADpdU`_04WjI*;pzA}k=4HJv?~aQPS8_5>Fb z$k=4xr;s8AeqXbq;z+h|v|pv!Bi$9Y7`^=@;1G{38m}u3a%7|GXN4c5B2l=*pL<)8 z=>s%YYCOh%Jpg5@^=_6+YT@wx&!<+0e9^A|r^=n3_aW>E=kk(dGOieAiw~@a;)X@L zzOSV*aC|X)|KWH7(EWblsjaPxHFk7`QwlfngZ@PYf$fecDH9R#vEJuDKVMX@s_XmZ zigDNVn)+b3JlLI{eQmHV5>};8yPh~r?XKG+38tbR?B*atb7g?^BUeSBXh~B`CDTRMh%d25NP_ zG?{-92-xCN&L$m#wlz*$w)_gk@s7QR1+MJG; z;}?`y&j-L4j(QGRaXpBcdqm$Bd<*Kuy7!ZJ{YI0yI+X?F|=dhUYYQ#KHBr5jSKSFg9PPKU$6*0n6f?W z5z>76!F2e66YkwB)}IibjF*hRSFB6lg_+U2Tjgw0L994#(~tNLf1~+lr`_)RxSYvx zdX?D}QY&kGv~xW1C+k~dmM}-)5)}%(rLGB6nL4r#%ly#2Og(1B{Q$o4dog})bokHD z*Zg}9^M|SSARpo@m?&?6><{(L{upbaGm7XqhkBr3b)1&zMRj=Rn5eY3+!I?4ddu_5ZF((Ip5l)15e2aj1M7P|!J z%{}$R+%wy5dvz7!AN$lo7s&!B+EQjQekc>tw2nWMHE2<+k4IGmi$zzg%n^EzRIfZyK7t z&4gdrFDE5so*OKRX^YW8Uq+c`ChB;O(Z; zXj^^`4L|1CjD#n^<^trD5sGavF zX5PLK?6yxGK0i6QP;gKMX}8?1zCDqK;YLsBV%Pofc!TASZ5nZCHTmp0hPYu`caLGy zL^LunFE*0epTLYiKL;|sL5haT?JkwljSzn-A66eWw5>FKkJkoeTP_f8&wS;1@v@sE zSf|hE^Am0_ETDJPpGy&xp3+!@2+`;L(Vl+jPd5xN@g>l9mqDQMqN7HQKlFzkfYf_= zu#J(PW~W{aUfgaUN39)(R64R;cj|mm&Ai^m!L$VBYsD#E2v$H&?A(~Z%_La9I!z(F zM$Fw#y^xuoQH*&_3ney9%}5(u)c=!Yk6j`kE7kJ+@wO&aZcL3Q(8;wNzt(FAE4uuz zj<2@Di(Z;PoD*5NeV=jUkuW{97mFWO*cF6lO4H8iv^nC6XV?LX7h=e3Lbs`A>W%k( zR}Tw`guu(`*D-xBeW9}c+qkWm0UY(x*`lA3gN)LL80-9#aee-Z^wpn9NV1b;IBVzx z3kKpp8Z1(QNQIXa{GzxRLKG3Sislq39bP1J1f)9a{3MVmxf?F|OwX%}Xi4>F=5nyHryE%VI2E)3BaA=g_G|1kh`%o8l> zhGXH7CfoI?YG?F%QO?mtIKFZDVEn$=FtDlmd#U8M9g0U=|19GSfbcJ)SM~M=!k*L3 zTUQt-KsuuOL|@~t@-?m9{D3A)9=E=?*mc! zQo{$nf|q#AJfb|Mybp!98b5G~t$;^?eB;}RzNldLm}J@wBS_u-daIte9WXkxUFp9b zflWi9Q6TH@pCSja58RlM9K@*1fqQnEoa(Ow01Y=>Mqm-DgRuR}K`C=pzv zrTDkW_!4!!juyL@JpS|hk>^3#9%f1ph@vUgud7c0!8Z)HpHfX|=uy6#Rm znncI@BY6aNm~Bz6-kpidZl9Uw+*bn5MCBA2SSZ5SJV-v}&D2^$rB-S|R!hCytx z3llxuP6t1TCH8qZ8s0gXj_pZdMmz$=aFTUH&WR!pGa@4Q96#lOzLJtp^rQSiBeqB* zgr@}R)V@?cs~SGtKQs#Os_Jz`M=$@N%kLgTNBXdO?9UP?e0mm=rte^8$J_K*G%?8b zRE+)jh5~40R?9gb^v6KFWp17M7`vZj?v;tx!Z^MS-RIkKVClk^hg@6{kU&1UqH{O_ zLhT~22aWn+&aUC{eqUE4H!&&ihRbN8b=1asi!Zzp?G^OAd<`4u9Qfj&*@Ee(iO$JR zH>l&?r_6C)5?^m!r5K9%@B6ol_bqIcLM(hSy-oS$i7v=RGo@UQFU!o3)FL7!Y!sTlnx=G|%5L!3U2)l^*kmp#DqhBsgd)YRP^N=C5 zSC`M*A|J=XJ}~|kM!4ZL7WA0$Ewo(9a!T0S1g?h%evBp7;_f*1(^p)ZG4SwZmM`yK z;{k4K@dV`>jE^13-rLj!hT~TmHJ6G2pHH0AzWNe0TR)jh$CRUZ+q>SH^ZA%)B;W6- zJqCf<3&`}=6x-K3eNCty!nVWKN3SnLW6)`{lSerU(B|@LH;Wz*+<&ETgy*FrSUr5E zbfw=1V&iVr7YF4L^=a+{%RRQheYJy8c;q^+cgMT#*_Vj&KfG_Shljv3CmqTiNg1GW zjW_YwvN2TwQHaMwqytwu`Pj z4CIb)jLRBpW4V7{n@xWNFeKkRL~WS_29g79GdI0(F4Cuq zOIzU6ev^KXQxBfrILINCV)mcUuV0!Y=#+mCucQP$jHS5`yZG)+N2!^j$I1<{*@Je- zpm3MGsbUUG7IB$cb~i9&#ZQ-p?0^%eaznF}-5^6_tCFZ{E|kA&-;t$VgQZL*l&u{Z zc=>zOP95UCe&lIZ+!M=u5WYNgs5`6(FO9waK)=lgy7G<&X2@g$txX5#xl5%eBu1H9 zLgXlolDCCw?kC`#kU1SitEZSB9K4tNU^YI@HX#lXB6q&rk$L4n28i;gU-)%68K+0{ zThTNNv|{x17v3nsYL15|2%B>E(AY! zzdYT&+0a>ckw@Jv4{y~)PEu_KqFLF^S?^!ZAv>11tZcr0#6sJ9kC zMTYzRtJjb&EcTon*A3^7{E+Xwm<6+8tQ@s}Gm&E8INQ~~Z*hD2+lIA$V?+*WcHvYr zQSZ8#@VNK%00c$!l)f}f!WH*-5vPcK#uqX=zX}RH0H;rKAC`>6p+}2SSdHr;@I`S< zwN;1WLaeNS-Le+OOFi6I#3}=nq9#T(ukPUhJD-7pDK8VPgTaZRla+#mudIEFiz$nStX;O1M~nlosEHx+)P5Vn zrTTos0`)QeL*~H;Y!+x+d_(TQ0lWWxzn}W}qCCd{)Lj!Y8yS6Z`q+U0&on)}mRcH? zdBqEE1l$uqI&mm9mRwsWhRw8{p=ZeJ3PFvjJLz7O!SG}G`Yo=Oa{R(%V?W*4fq`0Q za$h`c!R)rHmx?P|q5J$)a@P$q%yE76Z(41G&ZP%-=e|_ok@1>??t7|HfCU;#0+N(|br(c_}Sc9~%SF8@?v)31Wvx$AnqBSmCzZAl4k$WsEg?ZRzdMBsc zp&BAS%ujW6b-~)xyCFR?;Sk+8|82LE7ZPnZT1*w0aJKo#?Bn~j;9*Vn`zd9LT(!E~ z9JM*c-xucQlT}hf_0!6cI6?9NNCy zt;-ttT6!LpmD%CSU!D7IOA+8cEZH?C```ONDqU9Iuck=9T@b76`mqg9tgIvu=i&5_ zxLZ2X#&I6k7HkBS^n}t?Dr00{779O^UkF-i$_yM*X&6Nz`o|(U6KPes1`nNk0;$84 z6)e~NuwO&}MH)jqWDUL>?jiiX@urYMP-P6>SEQaICxn2_g}i)INh`eNaYya}PXzeW zFkjwtH4HTTRQ{Z5cEry)J_d{@JyE_Q_EhJQDrm3wa(?n)93Ni~RTSFWjoeBZu|cbi z_-_4{%uW6m;Km~IaCrC)ewbIK(JCH>n_kAkLkTI+_ka|*TQmS{${GuwtiHx&7`iCg z)JB|t0k6bdI>6Dv$1-HI7xSuj*R8*Gz?|d$Yi~ItActWlxKY9m-z|8HK4$VkGnzmh z9bS73P7T;7+O^E@c!L}9k+vXz}3OwOu)-((COt`U~dYAQ&QZ%l0^Mup?sJ-g;xzS zT-i2Swfz6$6QF!pp@9`JJd>U2j zFD0Sa2oLkR`89jH@JPdNjyU~9*tP4j2_`(pJ1H!N)N~_Ax*vSdVz3_>H|J_pViAsC z8v9iDpb{p&4@ee#XhM3{R*~+vWl z8ctl9Pjkq_?OPwmJ~~hbotn#=4vP&$UEd|L-1kA)z3N3dZ`6mrDkf`B%SuuFFxh=K zQLo4)aY^6Bs+O3;lE;=tOYBYU%iB52@(fG4tLYYdlaX5Qn)C2P0@9rMtZ;EP4feX1 zinFg4;xP%6RqRd0-8PHt9{jv`Na)ML4x%owb)Je;@2mx3^RwIyeHr+uC&@zlh&8T_ zzni)J`!;0hGOpL{^aSdhhVIKbkKuHn+Ti7;So}~EVI6g zK);1ig*9%%0~!1G)6^BBi_>`ao;$Ws%`3~QX5f#Psux~XUV8*c{hF1Z*r(mjvtE() zEdlPoHflNB;*IBbMr7GcM4?!h`p~?2Hbjjj&oHkzLfdan$26kue(h4gh#H*+mVGa};fe82gY(Qtc|n5#Nu9qsy`-;YEmj^mctEad;B#i>l> zM9&^bI=LA{gKl8C>jIGzdAbJvU@!=UPJcSSb&)U#^U$t)QCSN7I|O&X=`8@e{uX{Z z?w8>Gr_f5bJ_V=V2&e64dIwKW44ytHIso20uG=k%d;Lv;({*<)B;s?w$+LWx4e&1S zgx*epZv5z)bNTt-Ahe(xWxeyG5m*m9_lFz_h07JR_miLzt9WH^)*H9N1P#UY-=gJs zU*7IoaPk1)T)DcG%~SAD4Dt4l3I!W)^&Q9h zAZ;Kiv&&-;RLr%e8&$jEjVBaY4`9<8PHpJa5@f4E^y_|rJ~ces~(*lv1n7LmhZ4$1mv!*LUGH6Y6+SNp>nt{Amfp=C3Bz zbV9N0k*|C9gA{b0R`+9Q)xsmIpPJq#m?NLax!FV!AJo&FF`?f7-~B#L(w3pYMve3| zsIgbc`5M_|G5BVWxh`ZTnoV?hDWdB6*h}Oi!Q_3p^Y{MJUL~8fC=@G)Tmu(H%gBtH zt&rCHO*;7jQAru1T@v2jgyp?A6U#Csp!;+T$6pUi5aQis#eA<3plxGK?nEJ8?@-Go zDY;^DX3--OkykkE=F$ku5XAGziR<6z&SSts>U)Vq-LBmo`hnx-N#HSMb*MIAKXxeY zqv3sf6fR&#+eWOT3+GVtT=@4OKJbm}>>a zAnSmRgOI`{=-_AYn~WlIZr2&^A<7Iq@~BYUXb%gBu*M&!Et(~b4*#$b;vR;fkP*G& zx?yB*rJk85=8QV{d}Zz6dIlGx&!tIgzriIoDJ>SUA-H|&iA&HYZ){%rxK+X~5UxLx zSfo}jKyx~4q0b+Q{Q=*)BJb%u!}5Bjv};UFux6{U-xQu8W{jD14({D=P<*mU4 z-7U|$3|pbaX>s;j%yZ~Voumj{K-|e4;oRF_2z%5mjz-XB;bL7WU$rR(ezkRucO2e@ z*%q_W#^1u>={G5Qrv9Y=d_MhOzP}_VXm_C2n5@V9RQW@q8ToUg$xT8s|?UCP(t(fuQ)_|It(|z z3CF7Z_-5wMFOb(OBv?$Y0`DizMfNFYLbJ%9s}oy!!C?Q*rAV3s$hsPjr+(Ljx#r9aZTc{APPrWqP|LN$y$Z}$BAQPiZ`x<6*5Mu|pIUz-dLjsj z5MyGQ?1au=sW>-OwIMjQK5*JR0vj*pkFh5k10ARL@qnu-cz^KRK5g$(q>x>mJy)|A zqRHppm_@`Pg*LlU_4Pj_=BJicjz31o!dtQf>h_M3dQUU2kV|b~f$h)VCmOc@*&qI| z=j(OXnVs`xSIM!V*L?X46-d+;X+^$QZ=ifKcW?SH6_~N7oJwPOO!jb~rR({)dO6!% z!hP(h6o`G!^V!DTMn3fWJ_Uw$6{>@zsS8GNrES$r*(#J5PjG~ zZB)vVs2Ba_N#vt4n43N98c`>e`znV1LE#(p zr*IOEIX(_^nFd2o_FM&$_7EiL~-TV<`=^ss2^Ol2^r@q|e zep^uQ@4sd_Xb2@N=2JDbKP^{=G zIhItzhn4j^>4C*i#yoOTdb|bR7Ivocn%g!Ki)g>G#!gXtw@UM&`K#=vEDd9v&S-r??}s z#PmCOul&QNSX>=z-5P^rr6ghKLg5&tFEf7d%6XvN%8li2!p$c~GO({9+i#mdIi`QU z{zc1Rk(B@4VF&ilk_LawOve4nCBBROpOb^qL36)sV`GvP8sDtv{3Le^!e1rV+h0k* zlDwUd2Zp@iqM%GP=khVgICG=o`ymC~Ve_0p>xu*J7@o7-QMR9THO)2m8AQYH-9vZG10rThbHf~UQ!Tz&zYYW@_vAX!< zmSd%NVakv1Zw}Ev(EBVR#Mj#u)q`ZODK+^)mCaD(*>a+feoST5-7p8acFl}273~Fv zu9o{e-24CM=NI2W_k|tA+@E{=hu->GhJ!SxaM**PAoBjBQT}Zbf#e`|<^4y?gTW5X zn|p}81>A!_Keie7l5%#`mgTXvlY})?Z-v*KK{4Acc7p7d@cX#R-RHbM$RRf%{4=l# z7Ht;3o9UQg5=U&pRRJGZ6IHo)I=cwXtDUNHoL+$Mo5Q>2(>~(Mn2^HsvU-qYeLKRC z>x5R8y^bAbD!_LqOL~de^KyNCmK3Eh3|SpcK9kWxU_E(SD#P|B4olzeh`G~=ps?H; zmo$n$POm;!d2fKhcT(qe2{z@#;0oBOJhpV`YlBy%dv9U(<{P$@%kcJ%4TxSx^Rh9sdFIYdtokC zm8E~J*;WAj0f`32;||#N^^=OJmnt4s^h~0PeTpZ=Pc)kGcw_V-`;f?;%y=}w(X;c7 zI0m#*Qu&D)5`Dap&qC}%VQE0juFoYN-?{Mobs=&C8jZ`g=jUPoNI%Clt0N(#`Am>~ zR~n>o%qu>zehLZ7H=OUXMB_0NmX`CMqA}_4h!M%d8Ta))(;2gD?WXm!S$$*? zsvH00e*zz6xK)XdX_EF)?o@Y+;v&T~zyFxweg$Vvxz0NYBq|s-VN93D2Q?%h8 zK4kF?33^#0bI^3!m-MMa4g21>PR@Hb!i|Q>&@F`pI6XUQn7`c_QxdWs*o4@lLY_#$ z^UrlSuYcfxP<;w}x;S4r?n+w;>qD`pU9X|bn#oe7Nv z#y9TO<>5D%lYz!bESP5e%k%`*5#WD(QjuIN1}1r@{DrjQF|cWy@0iXI34C>$uJxbC zOXe0N#nOD-A06#JKS|76+AyOSYU4sBtH5A&x*fRISG5`xB8lwP&u3535PLVnL%*|# zzCjDN`!N-l9zr13aVLhp5YpT!Rw@b-3k(bd26rlJ!@#4>%B1>!Xn0jR5ztwIp9WSJ z7@f|cwDXon8OD>?Q%UoTTU8%-7vB4r{aFyxZ`6#UW*EY|vHqW2z91(*`n_}8N65`6 zeONC`%n`ogAVI;`48mcs&gd`d!=?I9)0ox!c9h5FWroW zp~lveT$da01{1S9rzSB!E>8Mm(Lf2FV-6x>tU{pQIURhyuLBs@Ie)cpO#t=|4peI+ zzQcrX)Qp?%B<7wdQpl6H{m;*@!L8fna%^tH!hq$oAxbAS+v?zw)5iX$&je?*_>Wewx036T4P7>67mi60tGuIkZ!1o|=%=vaD(Uam1(dn}uw%v@iuCscvAuYSCDtPMZ5RW&QSloI#0)$O{~BB0!~ZpifR7(NoP zpi!eF_6U~$)fZ>)#44qaa!Q)V;0;Axrfj+a9*vgqcHMXZ`_7CjO7#$RAvZP!D;Xsq z^O?DTz#&R_EqX5{K;Zy(?v)5{UgE(yOH=Qf;7r^oa?Umut-vVO53lZiStYIU#A>L} zZH2NgCAC}Y%OKshfUnrP9t6KJ9%3V$`L(H~UHEq;7|#7kU8?*Xt?cX0>Wz62eIFHj zb`7L56-5_|C;sQ>S5{8y zwj#w_=xgWPx99LRlv%kapmY5uDWH|};6Y_c62;%anOo~5$ZDyaa7zR@WF4<{Jj#>A zPAy1tVbqiKbF6~hL&t{LC%VUg<)kqNHteu0s%yd2!I~$Z=j%{qb2u3*1VDB-M_5px zB^o3+@)RaIz^6Gq>%NmE$T76sL@n|RPCCzMUwm1B)UC@!iGosa`dmtS^8-m7Q61zu zHl72AYTob}*G7QRj_rFU77yX&Gv(IWx2SOX5&vhJ?S+W(&;3+6^FTzS&+X>C6iO=# z56NUp!h6RB<*h^=xteMDO$C(@I4yEa=115;d_UNE$aU7!D@B48bGoi?^{!}!f)n%B zJv^pxoY)A-C)5n<^odb_g;Vhkb<&Uf_ZsoJz_M+kN)pWQQZ0HtYJq_D+HG%ni9HjK zPiRz&Rb$sZVIBS8EMSeS|HFJL569omXwnn&%0yCBFC=|$hR<{=G;HYOY`9u8) zQd4b?$Y(~w(wj;{|A7^9yB9h|q;313-|w~0W!oxsq>x%mgtD(O`;#zLtzd?jH|yx4 zXF@~d36HD)UP#jQB6SHLYHC^OCI5*Pe6`C1kfZeMQsgxt5kU0 zuJebQwg9x10#{Tgr^t^a&c#$$E|CT1ht2XX#G|O|yoTkJKge4+Jnyu!B=#^gaUCS) z1=or03EK6@4|JXheOE7v$IsW8JNw-(0b_^qQuSwfJQ-y5t#XF}aZYcfdR41I`R~D@gRJAJ$R<#5um_vzWE=Y8?Gy|~cJzp>Dj!$HB;(@(0LYLb(bdPcH( z^Rj$cD;&AcQ=j(tHplx%jS|mXt;f05o>I}}atJp2F8ajY7`A&YUTV6dkNg40zAh|KIs3tY zZVc~x&V_#2dlH!SRE$hGiTUEMyR;jeD&X&^x<0k#2n5{Ue|2KJ3)G)h5I1(!L-tGS zvPHRL=sLoGho9(wlc;4*(s_0fGIl4mQ-~-*%G1v>l{sW&RG=AFQyavulHZ2%6+MwE zmaFJ?PA#f8-I3z*`$0NLTXT?e4?lbleIcXKQG`tXT}JcLS@4CbG*{N<2kBCyqUAS* zIr42e{ukE7{*nFipPkL)Q&DnaRX-)i5FM5`KCx%oLDThT_rxk6p-cZU_BMTDE^?b| zP+a0g{1VmwXT@9?B)ChPlG9Uw_G_fqu$2sY96q79%PS3-f(BKcsO8YhQ26tgmJ}p$ zhHJ(I=z^WqRj+~YTs)t~q5iz@%3n6~|?F%le(Ol4svd!y6QOEzsAcQQMut2+9Sudtz} zZot~9z+7OqJZz(JCL3SP@cq7Ba~ix0P0wH2b`qaoXnp&KF%nmIghw?nhrv?Ys^`HY zf62Tt6O)XmkHI2F)!wS`g|}xz&5GCZF-A~wWO2M3PMNO67|ypsxb_37fk82Jn6oJv zixt9=g8XlpiT$X}8=0GQ?kUDmUDzsjkOf%Zrrk(1`$W?I!=w6cDF+ljr|G%ACp39wFlDfNq%5OdD0WF;hML3zdOP-tKn9TXd9b733Cf}Otu^TILk9?Q>OxY?fpV~_AwfY=(6gi9)Ro}8+n6$dMK_k zld5&i6A#9Py1D1Pfa~-7mb1TzLbBQ^?)fY>Wbfi}eMsEb9a`ndAHQay8;htH${EPaK=G0w1Sww9=9dZ zLq&WWewA&Dn0oV*bU*1@h_r1zR9U`W78*u;<96#z#bOA)Y4}F9XEKa%T=OiQ@+#E5 zFS7l+Wg`^qpDU**HbobPB$oDWTR8DHRAZCg2wTje{S!V1z@G!L!87J2$fo1GB03ce zSzFYyKJZ82d7HE1!M80SYv&$usmWw?d^)4x)$a(ER^NX)4uqqti}%@kGbKbWzqd(h z$9)_u?t8hjJ{B|SD@`4kYso^b)Gfb~rpQK@ssdVBZ-8CPVWX;cr~mo$#XNkQzBWvW z93RQMpx;YR)-70g5mBOnQAyq2?~QoSBVC?z9g4JDt531;5JNipRt?{mW3#yEri*AO3RtiXl`*nG z=R)M2?ydB&FMnUaeU5CnzyH>H?&o+oIlRYwDE9_3GnuH-6|-WK)SqAHjmzL7r`~mD zUr#t^EATF3I}LEO%&GZk75&T;LmyS0>_Q-dt=BHciEI|DYBWWwA^l|z$JA_ zqw%;6lIqC(TLG;IBF_^^F31Y|pT8eZeU|Jed=*`v`;Gqd)sH8(Q-|6Fkr+m_c7CaP zLJqf5P~s>LM!~IjCc6n=UH2~9Id!*}Y*=rp*~imPa^F}iwXQh>TYo>a6D53AWrkn< zC9e+%$g*z!Abd4lS9$wQeKVM9Zl>8q`0Bj_d#>%wE`my%%CiN8uL>w%do!2z5hNIo zGiDIJ>eul%=6J3XRI_Y8k~dX>@&w1yUyLoVdii2*B;l($!?ghg4+OEL=ADbplbiVJ z+eyaQJDpHk=GgepS4+O}wcL1b0DjklJ^%UYn%fBdhx|dD%T9`%Bz$$CgmUCUg%a+R z`9}SR=`1++^zexfa6(SQnK#pw+_0PGr32xsaG~O9;Xhxsm)Gw7DX>VoK+~in)V4&r zFX(b^zAzW|g~uV8@KqezmPq(2ysud^HX(d9kn(5@;j3VKl{_-Yl?Z8p=L%y911 zU}OW~s}z?GN%)HyqDR@$(*N(PT{=AdF7a?nj_vF}Up@LEFpuz6JS^AY`_ETDII`;# zzKR@Nithh>Rl+;OlJHen+d2H^pRZ2Le^!w9a0VNpa>E?LS2^M{&z-Li!(ZGw#x#Vl zDwp>y6TXU}{FZ~wgs(cDU~!xAC{1F zF(k2Ao-fHiVn`~H^qI#-d@+1?TUQy85AAQWXC=3{lWj*&=^WVAN#^(yYVlIq9=L8C zvza3Dp~K(o8;E=eTp8Fr{^dhHs$9EYB>JLy0hGb0w;kYjh0ws4CtD6ZsHt z994o~w;CMa9Lw`kmV)lbV#61Fnc>^{b}t7aA8N!O14KRqO!cRd|K&pmHlJ|XIxdp= zbnf=O%$X(K@Fd41{mMno^osX2L_T!DLAJIj$qLrX9gch^@}asLzOzI=1WNKY694j{ z^9h^%O3TM^rZ?7koydnIG`p8IuQgPkYW`h|qBXcz5QAw#J{GO!k{*&-~oDRQg@Xzn-Hy&Tv+~y1+S*@&RL+$b4`271< zpX*?y`)1=w!tWoqPu853&cw^p=XU(_d$nNIm{my<`tMh%$+KYwi`Qgps@It~>a=ER zNBI2|d7HZ+BMV3lc!e;DAAx;0I(h1f#qf2$ciKO{FMcR2)u%l~{*~X+FHiWrRh4+e zjnaIuC{nz_H1z~`rkiPw{pA7*Kc?2Nu3NGCrX+K4h$MVUm#HwMS|Y`NqFx~U9-@pQ zzE=`{-+$t%e0@X#`Q|9Mv>mX3#LU5M?P}Wi<;|V?e|{fFx3ih>dw4m@m0#m{4%Oam zx)Xj6Mi*aj8xVfa;3r==`dJV*-G7t*`TdbG#=^f`zUaE(vhvUG88qpoYh}~Hl4`)= zpWmO`UHK!}G7UGkFc|&w``y254tA}i!84zn%zu90BQrcf_&rkGHRk!}_t77{iJvPH zzUf|XC?NcPBu#blons-9pI)s$NBF%eZQ2XM@6kB2;QK$nk9hW`P}6KD(!SNx?P>Vm z`@R0^u1Ej;UQ9J1k??!CN4VVx2RDw&dg(wc$q=`n z&m_zK%rI)!NF$lB=v4gkdlRi2hhq|-K&~OxdoRN8zjoGT5PlD=H|89((h@*goO|tc zTqG1f)OEg1_>)yZrs?Sv}Q-x^wd zL-_qzs^AuRmr`8w%F@&I69I}$J?paP++ch1{&`ix?itzg%r8fl%tm`q9;mw7AeqVXt>yYPn zB^1i#-}le&_fEe)t3Kv|%X8-sP2}?;f9TnJj~0o(jJ0wlCBp9?9m)DY_&xjz(QMvE z_`Qxr&vTQi0I>QgO*%mM{n3vefrQ^<%(}pze|}H3=X2sA`Z!4c!S?i@-|MH3KMyz> zf_@c0KAs``p4l#R=CxP|p4WuXD#GuRnQus2repyVIWy~@-!t)C+)DU821vb$@{V~! z`lhkB-==ti{6FRi3c3T`3x$N=|Lkc|pgVjGy0%YXU9d^@j)9mk7V_+nTYx|6~b>=bi5T=l5Q&f$s^whx)gtd4CXo ze=6&Xl;Z7cN%F?9kV*(zB*ybksVv}V338{Ifd~1$_VBK>%L|@_3VSoKff=! zhKq#X6Ll4v^jz;&$V1zlZm6dH@6RvgYm^jyBjMz{lr0uL2VBV2(i5aZBXM~5o{52z zjVDe;tUq(zRYVw};-|@b0zCO6UBYndukKTR4kz2j7SMF_Ccvjr|^w0-B@Q0IP-gA5hE~vff zXX%IE8ve!lyI)N2YQFFBKc49GdOlm%vw6wp^yoXcT=vobea_o`^Vdh?_x>!syEXoo zH$#o-BbQvg>hX~d@At1xU(~(jN8TmLU#)nq{1<8eRr}8QdU<*JR?oX`9DU_l?{MN% zTXx^H-+OcW(+>>1Ig-BY#GiiUb7vh$50tjN@8je5dN+*Ko%GFQx%Ve8{okLic=^P1 z^-H}+zVwSeZ{0I5J=J*V8{S)&ec`#(=iWH-u``=vh*IVN0R8P|hpQ&i{{`KC)cU6Fymj$UK6F<)zTmq4XW!%T{^8Ai z7Y#;z=|80oUK4(AySLX{!H&Rk=xRTe)oX)-Y?yKv#<6z z?>l49Y;S#gulFY(-S|x4)ju6scEj@%qvCPt?{5F?XZQZ2^gXew%5L#g-Bf9${8d*8?Z^WY~}UXXt7$Z7F2&$-=u*JD5L+_?Kk>0dRx{!j0{@PhOOfBBc? zXFky3-F5XtFMs7TKlDEOo!8nr*L~MJeA{(*9Cz7m=?AtR{>0KyTl#yOHa%GPjgO_D zZGB3(_zyQq-%t3`zpwpO+M7Ob%Z)GA{LK5Qw$}z;*uLER{EGKf-h06oZ|m_#ejGUZ zh<9}H+dsJKUw`Snp>$i{%Rjv_eaTaG39wkN$6 zbvNvO<~qSU^q(hhuDN35Y+{PnG$zi9MEum8|{@2-CC z)81EVfBy2C4axMt@e3clY4}F()x#%#_o6>-Pp|v=nJ4a9{yy)9;mWg5xMOMh8z1_0 z{la&?k^a-Uuin2?vWr5mj|+t3g#{83m;8_Pw?K$Mc|6=WQK`xI;cp?9ORzkL-JdS} zBB4~leX8gcN)%i^VeLu6+M|mA@nY$&Onc$Ng$fHL61@DkXhG*507-qFc$4p+hFIi# zXAazT{ZgSyzAfQcD*aa?1OoMK(g|j`GZ0YjyCkAS7vPlJ>Ub9ji zj#CT1Snr>TcJDg}#u3DMTPpYzmKO+TNPeV5@&i|WbW6a0`IQ$28bZlXAWg^6qE0RpX*hy$@MD0y9j!azonA!zkJs(b3Be0JkBu3 zhcT4zu?Js2dh`v4Ut>|t2*Q!?jKnt0PL91zQ(&gS9sM;esu=-JE#L99glzEPj*cUJ zJI{FciQivx;P-dlf8IO2_Y80%{^#zkTD$(F!y7m6zh&9m_Z;NyR@XT{$bWi#>AvsE z{ATE-4m}?~>+rG<)Jf&h_04y`*u2bj`?^f~;B8CCJO?s$tFKb$j9*jzR0b>Xqs_0v zPc`y;2>G>Ko;Y7MIA80u>B;;oKcLO8Aj$QVn#}ktzmoLs+^qRg_#ydBF`vMX4!@Q& zXdOb;-Zn7(hD}2jA!ct``kV!1;U(vX$v5kLjVbLdOMi>P-m>_e(%vkWC$qPM%-*u- zO=)jg{1%11WzFZ5_O^lYkE5uA`R;p-_EXyX-l_{=XR5#N&38Yhl}~indoAXq(rE>rWTSH-Kqe#9AJcRI~=3Gn!;q7Bw%GC$uH zpdWR3pW>_G55s+eo4|VMM{@n~T$hho{;iL%N=?OA^c(?2(S3e>`P2MGq~{~`{z|cN z)BsLIxH_DFJ)FhdX8rt$rsmIjx^A23R+ywa^>bU@=r@9>Bu492WHacmSjaL%h>686T_fD_@`5K9#`YPv!cs*5NwtW&@ zDi@pD&h8TwfBuET^SWS!2iqs%HTj$vr#E9fNRRiYaZ{<%qZ_QGcGGxL3;|ZDKjAZ! zb@3uB#i*Wn))1cu~316D#iC5NN)W7hbnA{;CV2?@$+HIvk&5VDZ!0ly#&u! z>ad{{x#gaO>Oq9-zMdpcEyYnTkWLt67Ae0)`?=1)1%7*OfYK=c&>H}_+Ts|N!^JF1 zfbtLhNH>UOcO3LW>)d;!9oh+AOCJYs1Gv$BP$GIscOgHJ!W#=vlNT%i!y~_zDQEf~ zXAfFBSqc!;@=N5sTxb`>FE0t(STJ{79IgUybcXcdd+kCY$PGq0tL1is=qqv5!kUgG`H`Y{CR+U$* zDPOZjtgNiQU~P59MM?|BCsclhCDE3cloA!&5}sHn8KG)oPl7Jx zll&!t!0vE7A)VC+0%DC=R_UqmRFo}Q(hzPGo5IOJeJBxjH?}o5gyXHDmT=8V&&pNR zOGN3ftgKAj6iz0@WF#!gZDL!aa$VmZkB3{6BJ^4IYj184cZL<1ZP9S+ znq8udUFqwQ(J5%-;beQfmALlolpti}ZXAXuv@;qOI@H8|gJ;;S5Q%{F7Na-;Rg|Bd23?;;lXnot1c;fYu=79-)RvmeECT;BH_}AQe0X3ME+hU_$w}>mAXk3b!bEX2imh!) zQI=_jx=e!v5s-u;JuVV!Pm%x|^`K=$2@a3bq(J~%c_(=`HG0TR;beSIPM5RAt2b}j zbk#>TDbl5p*3gBlgd}&mr^;Pa?_?xLz_NI#*%OvV*AbP}ccmwCAz6|f~**7CNp z)n(=7ZS6_P4V9B?Q|ZX#qs2?ICK2Ei7l;y>3hT=9ohxOmvd2{#@oX>T&^sSDflE>@|rXWrFwswSQ83Xa(R=`W*Ri{DiTH!D1|&>>U!8H z=}J?=qb%jP4vCVYOKY%OZCF)PQ;|`2ngC^iR#YY|Eyh!{tNkStRp7uYWi9c9DtDPu z`oS!!YyWCx*;iWRD|P8t?x1W}%fgUctu!1G%c>=mPg;#}o~dZ8W6ds^SGfyCrxfog z5tekH@`Q+1pnRc5Jb7{Tnl%dON!WqMjY~D|6Mm5xpc_uFa^;r(Mo8Z$657Mn6)3g6A3e^LABehdG_HDwHi1 zJ3*dVO*xm8UmrAp6R}rtk3PN}5<1bd^{0$U2f5O({o?m~F z^VePE{EZYjf8up!^p9L}1zyniNh|S2CElonbbwHK0RUF6#qvTZv01=o0h8Oc=;P}|xYS;KxD>*P_#6*bCl&VDNtda4wvWHzBImDk8)yJo08B04=Ry8up=SPN z_;$b|qGq@sg%bp_mq`la+&HEr!1FIb99`${;K?4%yviHUPVicAweRG@k?_c_$v@`* zd{q$bp@c{%CASBP{|KrM^*^UmR>g(arJvUKx1|V|Y6m!qN4v3K|DCyZ7JGu^3mvZziXs>4*i65#%<3laKJ548ML z=?2h?Ai`_GRb843NBmMgncKTn`DD<0?cb5<`~v7b`77efDd&d-NbhO?LhI4cU7!~v zg$lf&JPoZ=J_49#$=B09w*GbDIZYq(LHg->0Qe&MRame4GTbNr#ok=F)VHDT$NM7k zTQZajSAq4~=ivS{hc)ZqXMNb31o8XO>^)OWaN8RkehWJVb4|V= z4aeRJr4@5cALcs0^t>mn-?VPibD`8u_v!s3dhV0%6C9OvUkje@({mDpk5+Yv#xvgo zpnbhrz6dYjA-wb)tyz48hxp_82oK?<@e`j~av;3K7vVL+M{*;)h58-2!TW);AT#vL z`*-~JIfw9x9R2U0w@>s9{ao%;KM!?;7+oo|4{TH>a2<642VOccLDV7%K3>s{K0c zGx>hos(ohh{BBFh*TBN;@dv%%0qQ}VKdt$Wpw}wYd=p+Mo&89zJglqD_4wX8NfZXt zT$3+I!Lhf(XoDckHGMb+_?3Rgvk89}v-tHIe#f)v2+19OFYlDYh59|r>FPP>hx0pK ze6tOY{BA(`rgMLfup|5T{brjrg&yaJ^J@!J(<7Q~Z|wV;(?c{H&`f_(A5N($GJ8|` z;rz~qjPjwu^w*2}jlW-8H1?+Q!};a;yov|)^K_IK>Hd~JTs|_Li+zh{f9>Bt8~bac zJX-&EfeX@?xj3f|&oh?*<+J#6A=c%yN|X->_9Bb<=C@t=<^74rL2rX>=-THdT?ftB z8~3vU+6N<}R>^Mao&fA>!#uy3N9QKrGox4eo|{POlpW6&{c}AmKE!y-**{w47Fc}f z>>sTXYz9xZy*c~Gj9g}Ph4~t1|2QM*8F%9QS>_+)^&VdB&xSYN+JxR@V=`|Lzfqp956>%C+c9iQhDpk8ivG*&nWdYdw~SSbhC!CB0i}kK8P>I_aUqKL%CH`33UJXG?k1#%JEf{ zUx_koA-{lXxUH#)Bv`4`BxQQkF|Yo~UsOF-*6&=`A9wE_iU^>e@cz1U(u zClP-P_7Y@@p?ywLGHfQF&Cf~PXqSwPS|xi;AwO!vJinMf=Oq3Y&FEFW=OkL|jO&G5 zJJ9kY1J45-sb!)3NY~GSP7l(v%8wLYpQe6)$NigJ`I7vyN;#gD_qj@3OL-95M`pn( zmy`#geI#$Uy3Y6W7$2(nryqRp@qhjNH(fPUvUq5{_jA9w_GrCWO{LZR?Y(hpWY??b zT}&nMK_%xG`8Yr&@=N&$%kz(4eDuZ3zg7Q%YAlhii%QDJ5dHPQw{RHC8WxYwdOif? zfN!6VuK}n`XWr`6RxpIX|3V zY5ubHnevaM&y(h#>GN#mA4#9de>m%hNyB6MOzQ@f&iY|ejuwJt+ncj~OjEGV`Y}y` zF>uT~TDE=|M<^XLVe#Q#_|p%M(zAt7w)9>-@E7ex4vKG<}HX0 zm893bqxx_JKVQn?c^_oxcQ7;h^PX>h%*YQ;{K@fy^F{Zk8mCrXboke~exp!%(e7UX zoqnWeRbCXvIxg>XrRRD(j`Zz3rXnoar6FL zmc4yX!QaOn`1HVWGC%#VZ53sH?%e8q>FCin(qr#i`moGz{Is6HGS}DEEq}@X*z@tT z4nui#J>0*2-H{jm{MNR|o~-)hCNZ&e%roivGCscP)^Dr*@WVHJ=-CTbz5CiT#;>V< ziu1$yMScd5pK9dy5b|reJZs;0(=E+c&AwA=Zj|N=<#be~2mCyO@>za>^9y|4cM$kI z#qxXs%j@%Sk@!d~$v`ztf#Rd*D@j+raFtiu1$lZ5?m7y3Xvaiph5a z>No1cBzrr^^t({@wx8LX$`9uk`62r!eIot0T%OF{kT2EV&>uZQ`pxYP<$K?{0^8dF zvp2GTk`LM2L9{oOA1+_eKUJTd^<$a_>8u~q6c__{){mTc%~?N~e();Vo3nm!!I-S0 zy;-?_WWP`7g?-1~0gQ_#onOJeWA8zXi!6^vxfo!)dvUx=s$t*JbOhHyFRs&vVV%4k z*UJuEFOMFAIDa|Dwf9ciPjPzFtwS7i?o*)GU)|67;rt>$)eslmTLpY~P@H1%A@6kXUw5%HD`5ugePR9A#H^Ak?`QiLdcm8aE z&$hQTv$sj{Ik{0#d99owHPc+f1N3mKM-9&J%|&j zHQ!@@E$n=g9!X_(JnQTqvjk)2(%C2=GtH+p`azPC0>KgrJMy%jygR_E=XVImo_+~rSH!RCxadgVLrvWd{$w;Ki_#8@Ec@PsB>$=YDqmX z&MRtH13cwjwfJ}LADa@;dJc5l4SGSNuD}bczCW*pw-O0eBB9DP09knfmTR%R5K3$o zuvx%n0h@)308F?TOM21v609%4(v7870p}RU2?Q6z?_5)V{{3r`*D!uBi{SY8V2Gb? zeEyl>`18;{WULp@lL(HVGimW(EcfYrtp6O)uVK`)Vm}}2DbMw*Bv0-0u`Unv(0|^W zpO5vT|0evrBtKoUF4sOe+&y^mzltPQL*Q>Vwj!^GWl!gwMs5CV{bgK)ww}GUqyB^ zoSQCVT+P2~q4QeBhZ**g>ep;Q!BmdB~8R!fmJ*)gfq4i`6%ah|- zdEZFo6d=WO3**@|mB-%{82;hGoVLyM*GMapqRZbq_-q@kn>xpA8!?ly{Y_gerHcoGowU$i{*O8f3esb z^S7#hSTBt_Tc721q^SS6d{LjB^~0iBWBPoE{07P0A~G{Z!};O-&KU9Rb&l zuxZ{&?r3kSzc%V$=yuKz=eN-G^Tp5fch0RJM)|n9Yhj;7d4+uC<@BFh5-8O7rF$*~ zy$UjMXy?niwn2~F#MWs-iGo3Xj_=HYyRPT?vc8W(FGfbKl3w?2(T7tz%#(}a$!87i zFf;G@=Cib(121U+>Oq`$BY#;M26)n|d7>`PFi`?pdC`fF<@y(^^P*b%+r2ASf2W?P z@uJ^165qbZ9(-N;{Y!^m5{Sj6BVUUJIwd;C-li0b1vef2wLpkED5jRLqt7}b%d2T> zdFO?)pq(9l3o2ej?$}$Qr0nQ#p(G1|DZK1lxG-3ezf4`+x~=K0LkG&)<))MY!QR;rF=+jz4c)hj0@Njz4!8M7VBT zzX%^+&mss{i>DX_*WU#48Adt95YF`vaG&6+uwHi?-0wshnoBr0Rgv@iWm5qZ)4lPf`@Z{dN7E6CW0rlO?$Gn`Qw}%Z{bKVn z*X;-G=9Tlq`L&xrBl^hi29$3a#&h%#$k+Pc<2B-kw{w0tzZ|{@>)G~J^v|y_{Y8B^ zrKZU2P34F4TZHqU!xGb9FY5RDBC|J@AI`5dm~4G6`g0+sA1H5U{m4xWr^O%sljk|BLeKS1lfvwR({sG^oGkxd#_V!4 znHuMZ^E>FqpGM`xHQ0j+bWPShh3R0UpG^?g}7KjG&zR-K;|&v|pnXU(iLh4Kfz_W|{w z!F)&1YZYp~39nRU$FoJBe`N8j^ZnqgiL~O9#k0=-(F&pF;>fl)XaAThn`zfDU!#7{ znE8jI_h-!B=G^{KnlQ>cQaSB8oXrlXAMAT1&i9|JngjMd0q6T2RtYwPhwO~jkxWYw zUNL*~^6zEX%`)eQ^J_PMM)aAz&AIP)@b4W|d`dr0M|qL%&*{S%$?aHcFP{Ci|BJJ+ zzc$LF_4fc5q%X(Xd^_XOmjLCn`18cp<+BQNZZh!&(Ayvzp3b?+LuTxa`&j|)gOO3I zWH)v919r7xo?pzPbCa)`(W`v(q>?&i$FoJhUuW@Q8skUj`;Qj+1s2ab`$vo9nuR9Y z-sVdFk@7Xp{xNGJt+-_NHs|(_AcJvPkEQ2&JC5}2JmcLbet*e<-`{!vdGGYzGr(o! zf9~F@wd+qhym9mXTb8|jPr=`J8u;|UaWX&suWc1&e(v1reM$QMQ+n)uOCOf`ji1&N zSmyfLy5%qVAA3H2)?p}*u7~@#uRHR>pWoW{*ppSC+$1KJj(HC7@#I^-t@gtY-|(Sl zFI@HRYtI5keujTTredA5HG+#CQPN}(3nlF^oQI#I>^9agk z`2o%^@O9ro;PVvAfA0|H_3LxC=sy;U*!Zb1D;eVAl#2bq2s%HH-fdsF%0{31VO|D;c(|CY;>*&Fhu+8g?# zM@YZ9y`g;XTUTIv8({WE_D}L5dpn5srt-t(3u>t9v$K9o(=MI$W10eE;LiGy6R$bz z2h$H;MSFAB4=xy!b+k9j)(@@ceuwb86hY+6=)7X&JCJRoysOFKIAF(!1hk&}jiDaV zFe~uF>gRs>_f(4goJ4#a>?KHo!BYF2q~u96`D}hp;zqkM8|L}N{5dD_ zA2Op?`JR(#tuwCuxptuCM+Tk%I8w_(`H`+?fKCt6v&xSYUY`~T^0%r=Q9v#MEPG-o zSH2{_tTOw10$#{F?j69qNOcyRatV3Iy$3NbVtGD_(}Q?tFUC7dsv+;#bOiUoUfic2 zhJEtwxL@wT{qoU6kmp;Dd98aVDD0+a_&@ax%`>z5y;D z&JX9;QsET_S+>2UnY~TQ*D-rLTo{%zSed;YVEUUz{jSllxAjcF3uSK?Gka6{;rufD z=k{j#?{_kLL%*c@Bb1M--`w8NpV9eA!R(FBbI9Jv{<*y!LVLq}WXC~fZ}RgF+4}6P z9~o0Jb>*xdro^NP56Al*>-FM!A7p6Q z%)IBHA6u;CZ|FPavfj&o^!@QgQa(q%c1gFP#V0ol+WJ~@AADgQpcP>0pX}dj-TcH| z*DsJT$ao_NkUw3QDY{yDzFy2%5x<4X^OgJ*W;KQMtjhCgN4}1HvnAl@L$)-mzn;7DHOfEwUxIxL0)xN5akJiH>132;vzSs2eX^n5D_pM)-YE8|b^>piOq8qe{ zZp0?KF_Uzse$T`GU!dPXR9ILy7YRq%AL+CBKL9V{jk--IC|5qL`;t&kVcjW?EeX)N z*^k5O!m{s5n0Kvn{MZf99z=L8xVmUA9D=I_t;btx;Z{pXd3-^T%0M#Ox|;x71M-s( z386KR*wZ3C`p_2N8BHbxAr_7+4?-lPE#W{GJng3uEuoolNzY4+()#f`u$%nW`KzM| zd|m?VbfKo5`o?qZbmEUtw`zPd7L3zzRwTgfv<|8IQ4h52uWE6w{b|98u3R`86vTnY zsd*9Mc6geM?5hjco4(gUA6?kd&EN+91nnblLrHPq5cVT{y$gYl!Q-G55#Kn2>v|Wo z_niVI@ms7V`428HtNe%c@m{B?IE3rR&>JwnTJu2q(e--bh~Y$+hY^mUYqFl*+jSBCb|Qr=#n3)zzh1W$r`L*faO{&FU0a9 zEHB2g3d>8dq;-+jd%T@@LHQlZpNt#$Pa0R`|LOZ<;(yct&W9tY`-46{Kf(3T6`_CX(5hXAxK%7K!D!5=A0=7y(Yrjx|dZ4urD0x5VNf5c$ zf*W6v3rB;cIG4x!#T(}inX)$?=k~v&@3&kikl0`J;V8}>Gk_BjU+{nR@zFdKYiYf| z95yw7*3%uaiSDRPbjNI>J8l!*37hB&J@&k>S7M4T`4x%>=USXQV&Fe%T(y7I_p=n| z4jI7tP+-2J`uHf$9Wa2S_|1)ZGMbM(LNVdj zigQa*547Ufk&4{-RSRx#T`nAro#I@cuP)v=x73uq@i?~!&ktzayrej{?gWq%Z>KuN zxx)r`@4qFZGXU7t;K{Wj69wTW(>DZ1oWC?1?^ zaqggj|D~d4^vx*Foxt;X z5e3lyUXU}%snBw9@Y^c^tvFXeJiX8@y59kQ})K= z+!WdujhmM)yx}`d-@j3uJ754OBEE{#_3?2&imh(Fzl@ohKkMms+C(>H6WuPG=yuyg zx5p;By*AP9GewvD3B`kREza#T@Sij;@!k4*8J0^l2XvVMY&>qBLX~D%( zxo{)}igRP7(B8ca%HoZ42Ta);k8>kvUo>uBy6}ekOc+0Jr#i*Cy#{b1b|_u0kB{&c zYiYf|95gk5*3*q`v*&!d(NxaxNT6gW}w}v!T5cpW`jwIJe)Fz417= z7VV41%}W>FaJfMayq)S4=XM#uiPT}0K0X2~*3x=^Ibdr3tfxC@6Wt-3=nmUNcf=;T zqc+hUvx)AwDZ1oWC?1?^ac-x9|DXqXuvk=hor+OmgNW#cxC9 z`gD1}eCyWx&k0ldW)$c4SArZw9AM;PsFR%X9kYvO^_ike{)FPe zxfbUJ*XsLO8rO&c9L2e{7wY5lp}>X=;3&@Z;rdK+<|V~%{Z;yOdB1$?*85MtDSb1F zb9>f<97G&o?WIsBIpsTUr+;xvKr7De-3WT16~D%whW74*1UL0}Ju9Ap_8=1j#kuZF zpxuw}s}*mYTWiYRc$_PueX-%IRTo~3)_@$;26jPlZruibI1&2|8^AI2MOU@nU)GtL zKkMlRZK4~oiEhj$x}7%BP1!`Z%O<+rrs$GGp?Gkv#kqd3zMrLW4I02voLlA7$LB+V z^&7xZoa@H*ndHn%ir;!J)2GY(#+^cRxpPQ^&cf7oa_;AqMgn$%_`yZ1 zzQ^d+;E!%o{7P^W_}ydro+E$Gn8qdIcf|;fKc_){a1_6fOmIBU?L$UN@cRt}$M*@u zZ?TrNzj0j-dQpMjr7zz7O|L0GOZrhlf=9nfRbIOA#^8rQ4!oV}w7;qPus)oK9r_L6 z2yd~L)~}O&rsmIjy8SlM9k7Y+piOj#Y@$1C6WtM;=#HAAOMZpcKU&wVTBqxXfJG(v z?c)Vn*WFj^`&k-SuK^sb>!sJ|q}nbz=Yv7xh8pRQK_nclbFe~y{b zH>3Sca4X0`#DSGw4|S5$Ovmf=n;R0)+TTPz4tk)qzo~l#+B;t(xT*Iy!~YHKK_(80 zbH~vRU0VRIc;no0Q})K=+%X&%8@^g~;Z@&tFn+axT~M4WeoP-u#C|;na14FXRjv1z z6Q<_Rdb+~L%{=F1J>3$U=(=p8TWS+s(I&cXo9I@UqDu~i;=#EV=eoA(`&k-SmjN8b zxk8;jJ|7CK(*Ta*+;Iaqir<3U_36?)Syfu^$Er-}n^BzW4}cs*8fX~mBqzG_2G9eoIJa*hWGsh{gHr4HZE*>-2buUN&K*HJoY(>MiZ{;nnX)$?=MLWh<6^^C zt1i6i4(h{EoLdsohZ7NB$^cGfphz#Q_m_TC^JhKXTAS$B*+e&J6WxeSbYnKr?X-z* z$`oC4D-;jTwK#Xez<<)XVmtNyF~zxK25>$USg>9nAH}&N25=O=`5X1|(L7mITJJx* zOzE3ZoLlh;kb{T=9czO+$;qnmJ9vsy0$Ooy73x8uxTZLF5bba@0(w`xac;LMd*gBL zKvdt)xKO~IyY%5G&K);^6A@peSs!1a=G7{^*89sIQ}bs%-CmpM_Sr`uJ#` ztSYVdpChL9%_zJ9G-rqvwtJ zbGxLE;|z{J_fUso7Jmo7n@RY1-Z+SGeg?P&6Nf zF0J>Uou>57D9)|;49HbP0gQbC>LjN^%f-QOuLQK>+$z+ALUBiNF3$%SZ=9PlWp6yr z9k^59Z@EywouAc*qd0f`^ZIZi;)~p?4_BypwFED9 zOOoyqte=SGLM-XLgYXbu!b5nC@F6<2AiQQvwWG-kj#uv1y%V^X$98&FT^WNsAOeuD zv+K|;CCP>$WO1y{>LH6!hN5;72i0Yqw!1}mj93wkg+JNY3LdI`ze&Vj{t*1L-6J6mh zSe<5jyd^f#b=gF>)F!&3DY|4@ln2Z$^2p(g#7VA`X1`pP){1DwI4Nyu~2_tvr{AdQd1X zDbK~9XDr@4SA{8i<9V)L{5@qYIl8bR*sJf~D9<%w04E~8+K2S~67YRq%AC1fZb&!KdH@*XPAJ*MZKs`n6 zPI*j8fXBIAIJ(;Y!rBMKgNp_77u`Rkldq}8Oa7u{NFUCJ-G}!B9Gy><{1oab>`(q; z;I&-1QLGF2{uB9&6#m{Z;p;~K(cf2CIZZ8%%w5_qaDIw+zmPKJxA=Zx_%VGsyHF(E z-_VDn{X)q%_2ERsmok9M%tUcsS-2}*hx5p;By*AP9vx#oMO>_rrqC04c zE_oGNCuzShXMU&2z<<)XV&BsD$F%;B8Nm5aV8L(e<0H8iYiYgz95SVE*3%ufiSCF^ zbVp6mh4?1(p8tq}zET|O|E|7X*P%iW8o&h+uIh1pd=Z4}H-L*FTx`ESzD|T2Gk{AW zT<}SKeAeshn5p@*p6<9!bSF&Fg*?In%{)TMA($uf(>Q%jF;65wc?9x5w7)KWI@f;d z+gf*rp60%i+U7pZJ+4)8PygCBXHP^r!zI z*UN@*05wzY+7L>Hk5mPr z7X1l8PyUzYu`~_XCquv;5gWRhUi4tUf$u^83WV$Wfj&N(?~)(t!;v5CGJr#}mKBAY zN0+I2G+HObXF+ZxN6QB8Aes{r;Om4BxgJ3~q(STqwKmAtjnU?C#`_CGq@gj8eNS39 zV)3?52#Gx{Eiyd$U-A#~J^7FF_uTID%imuftxs-?hhj3_#R~0|LQSrNUnG7ONx!@) zUzbWRfXJmwYKFEF;mVCyZ@EIcxAofVGeiadQI{uJU^FCiy!OtZ<6pr4P&|fe>=g4v0zBTJ zRnz}m?z&XpX6?R|{FL=}nJ~1AonM-~pXz1f<*J&KzwS5saAdzD25_9;eCvgq$GxWJ(a68WhCyy5$9%`@^q*T2;Qq~r?7Ptp zX*7k}PjS1Sd;6(-&<<&30EuPqr!xLDv!5De@+CP_>B5VFpXmEF5#g%-RUeN0>3{(o z`2jzEWr6r9ma=gE^mC^CY2oPq)3oTPa6%^UC#~8~Jz+|(NgjpgXTK?aHeI&)YQ+-K zfXFK4&v?jxXMgbgP-Ei!XfozWwl~E?H+e$I^V<{Q`1!lyp`GD)py~Xb(bn^m@#u{S z`69MQxm>a&+7fGvC&jjeCl*RZsG8W5pvz>mCA=g+XA^;dSRWlNScgd4@C za57LIN`&2wZOskgxSW)#S?O81s(Ohi{gsuKiJQX7gqVzkMY&CEYgDf5+vD+YYf^+> ztHq8;v_2vxB5m!>4dTwQ0<$d|Ze6oWl(8#)Ju*54Z9JT8kGB%no}ChejNFaG@Pu|I z@I+Q^M)H`A*A$COT+or@5ua87` zhh>mZd@2Au0FnWALwlo0BNd|wQ64Nzj66ANOHF1Lfq$7BX`*F5JTMEFDF>(0L6j;v zshtqy$}d}(D2_(4wJj;iGR;tzX^wOz1lXttEh9>Bc$_8;0@%ts$+M}^ zLv9Ku<9l+toGo6xdDEt=KC(%XE{(K?E@UMnxzjyW?xK1pBRK+=#Y4@Wur#`ksHDCt zJ&_B^lH>^^2$kM>3WS0r6z{AF#XbJZuiOY);x4=S@5(%lZSj^+(oH>AtzH>gnKLP6 z&23F(VzgD#sLpEnA5VQeES)|En&NHkF}Ko;9i$nrRA@DUnU{gm%BSgN=OvPHcN736 zTW$`E0EC#gD|mKfL>(2+BW&`>3@}P;A%XtmAClqhmy}e?`DhWE&;9e!3Ey@>S%brBIxl!bO zWgSrZ2b7Gw$8qM|X&5F-0Tiq&kPSmXQ zqUukHwY;rtby<0NTYFM+L*?Y!R66qbXz`M)Nd!2>1)@Zz!n(42=Smr??6Fi-uy(a7 z9%$hP^$N*i8Y~MC6_k|ZKgpJuOeX- zfl|m5rmlyLlCCr*Jjzmz>yRiZx^#%;RvT8;)Kp}YohCq8jun*&ON;Ro?P`C?L=`yj zN?A)hp~_vRlzuRa>e1P1W!YC++? zU^D#}P0=?zZy1A>mCj>qRu_l-EK7i&H&A}A=QWDBfT8RysC*~i=X?w27hW~A3;&lV zpQnzq@$zY)^VEUg=E{Y`iFl)qJ!f3?JLp&U-%wKi-@SmI=;D~5PWk^n130o@_ddG3iv zo;fGfE6bhpRONxJIengbL3QPY)s^s_2*{v6=o=rsx}_K%51}2>XbN?n%I$vcou}?WJEWBXB$j;+ zm+_~W^VHN5eLqB}dUZ?n;Y6IE5d%2#r*-er$47o(%m9w`Vz$e|`O}+B`P0JDzhheT zQz-b!`vt4cQ|~vW*Cda^^YcYh{5a>S&Uvc*qMY-7s&k&&9CqGM#kXgj_fxaqH+Rlc zo%2+BZ`CXA5uaGq;$h69SJxRa3tVJU|vXo@)6dbXFf2k{EYSV MzhN`|L#F8ef7tYYjsO4v literal 0 HcmV?d00001 diff --git a/test/analyze_block_structure_from_gf.py b/test/analyze_block_structure_from_gf.py new file mode 100644 index 00000000..cda63295 --- /dev/null +++ b/test/analyze_block_structure_from_gf.py @@ -0,0 +1,179 @@ +from pytriqs.gf import * +from sumk_dft import SumkDFT, conjugate_in_tau +from scipy.linalg import expm +import numpy as np +from pytriqs.utility.comparison_tests import assert_gfs_are_close, assert_arrays_are_close +from pytriqs.archive import * +import itertools + +# The full test checks all different possible combinations of conjugated +# blocks. This takes a few minutes. For a quick test, just checking one +# random value suffices. +# (this parameter affects the second test) +full_test = False + +####################################################################### +# First test # +# where we check the analyse_block_structure_from_gf function # +# for the SrIrO3_rot.h5 file # +####################################################################### + +beta = 40 +SK = SumkDFT(hdf_file = 'SrIrO3_rot.h5') +Sigma = SK.block_structure.create_gf(beta=beta) +SK.put_Sigma([Sigma]) +G = SK.extract_G_loc() + +# the original block structure +block_structure1 = SK.block_structure.copy() + +G_new = SK.analyse_block_structure_from_gf(G) + +# the new block structure +block_structure2 = SK.block_structure.copy() + +with HDFArchive('analyze_block_structure_from_gf.out.h5','w') as ar: + ar['bs1'] = block_structure1 + ar['bs2'] = block_structure2 + +# check whether the block structure is the same as in the reference +with HDFArchive('analyze_block_structure_from_gf.out.h5','r') as ar,\ + HDFArchive('analyze_block_structure_from_gf.ref.h5','r') as ar2: + assert ar['bs1'] == ar2['bs1'], 'bs1 not equal' + a1 = ar['bs2'] + a2 = ar2['bs2'] + assert a1==block_structure2, "writing/reading block structure incorrect" + # we set the deg_shells to None because the transformation matrices + # have a phase freedom and will, therefore, not be equal in general + a1.deg_shells = None + a2.deg_shells = None + assert a1==a2, 'bs2 not equal' + +# check if deg shells are correct +assert len(SK.deg_shells[0])==1, "wrong number of equivalent groups" + +# check if the Green's functions that are found to be equal in the +# routine are indeed equal +for d in SK.deg_shells[0]: + assert len(d)==2, "wrong number of shells in equivalent group" + # the convention is that for every degenerate shell, the transformation + # matrix v and the conjugate bool is saved + # then, + # maybe_conjugate1( v1^dagger G1 v1 ) = maybe_conjugate2( v2^dagger G2 v2 ) + # therefore, to test, we calculate + # maybe_conjugate( v^dagger G v ) + # for all degenerate shells and check that they are all equal + normalized_gfs = [] + for key in d: + normalized_gf = G_new[0][key].copy() + normalized_gf.from_L_G_R(d[key][0].conjugate().transpose(), G_new[0][key], d[key][0]) + if d[key][1]: + conjugate_in_tau(normalized_gf, in_place=True) + normalized_gfs.append(normalized_gf) + for i in range(len(normalized_gfs)): + for j in range(i+1,len(normalized_gfs)): + assert_arrays_are_close(normalized_gfs[i].data, normalized_gfs[j].data, 1.e-5) + # the tails have to be compared using a relative error + for o in range(normalized_gfs[i].tail.order_min,normalized_gfs[i].tail.order_max+1): + if np.abs(normalized_gfs[i].tail[o][0,0]) < 1.e-10: + continue + assert np.max(np.abs((normalized_gfs[i].tail[o]-normalized_gfs[j].tail[o])/(normalized_gfs[i].tail[o][0,0]))) < 1.e-5, \ + "tails are different" + +####################################################################### +# Second test # +# where a Green's function is constructed from a random model # +# and the analyse_block_structure_from_gf function is tested for that # +# model # +####################################################################### + +# helper function to get random Hermitian matrix +def get_random_hermitian(dim): + herm = np.random.rand(dim,dim)+1.0j*np.random.rand(dim,dim) + herm = herm + herm.conjugate().transpose() + return herm + +# helper function to get random unitary matrix +def get_random_transformation(dim): + herm = get_random_hermitian(dim) + T = expm(1.0j*herm) + return T + +# we will conjugate the Green's function blocks according to the entries +# of conjugate_values +# for each of the 5 blocks that will be constructed, there is an entry +# True or False that says whether it will be conjugated +if full_test: + # in the full test we check all combinations + conjugate_values = list(itertools.product([False, True], repeat=5)) +else: + # in the quick test we check a random combination + conjugate_values = [np.random.rand(5)>0.5] + +for conjugate in conjugate_values: + # construct a random block-diagonal Hloc + Hloc = np.zeros((10,10), dtype=np.complex_) + # the Hloc of the first three 2x2 blocks is equal + Hloc0 = get_random_hermitian(2) + Hloc[:2,:2] = Hloc0 + Hloc[2:4,2:4] = Hloc0 + Hloc[4:6,4:6] = Hloc0 + # the Hloc of the last two 2x2 blocks is equal + Hloc1 = get_random_hermitian(2) + Hloc[6:8,6:8] = Hloc1 + Hloc[8:,8:] = Hloc1 + # construct the hybridization delta + # this is equal for all 2x2 blocks + V = get_random_hermitian(2) # the hopping elements from impurity to bath + b1 = np.random.rand() # the bath energy of the first bath level + b2 = np.random.rand() # the bath energy of the second bath level + delta = G[0]['ud'][:2,:2].copy() + delta[0,0] << (V[0,0]*V[0,0].conjugate()*inverse(Omega-b1)+V[0,1]*V[0,1].conjugate()*inverse(Omega-b2))/2.0 + delta[0,1] << (V[0,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[0,1]*V[1,1].conjugate()*inverse(Omega-b2))/2.0 + delta[1,0] << (V[1,0]*V[0,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[0,1].conjugate()*inverse(Omega-b2))/2.0 + delta[1,1] << (V[1,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[1,1].conjugate()*inverse(Omega-b2))/2.0 + # construct G + G[0].zero() + for i in range(0,10,2): + G[0]['ud'][i:i+2,i:i+2] << inverse(Omega-delta) + G[0]['ud'] << inverse(inverse(G[0]['ud']) - Hloc) + + # transform each block using a random transformation matrix + for i in range(0,10,2): + T = get_random_transformation(2) + G[0]['ud'][i:i+2,i:i+2].from_L_G_R(T, G[0]['ud'][i:i+2,i:i+2], T.conjugate().transpose()) + # if that block shall be conjugated, go ahead and do it + if conjugate[i//2]: + conjugate_in_tau(G[0]['ud'][i:i+2,i:i+2], in_place=True) + + # analyse the block structure + G_new = SK.analyse_block_structure_from_gf(G) + + assert len(SK.deg_shells[0]) == 2, "wrong number of equivalent groups found" + assert sorted([len(d) for d in SK.deg_shells[0]]) == [2,3], "wrong number of members in the equivalent groups found" + for d in SK.deg_shells[0]: + if len(d)==2: + assert 'ud_3' in d, "shell ud_3 missing" + assert 'ud_4' in d, "shell ud_4 missing" + if len(d)==3: + assert 'ud_0' in d, "shell ud_0 missing" + assert 'ud_1' in d, "shell ud_1 missing" + assert 'ud_2' in d, "shell ud_2 missing" + + # the convention is that for every degenerate shell, the transformation + # matrix v and the conjugate bool is saved + # then, + # maybe_conjugate1( v1^dagger G1 v1 ) = maybe_conjugate2( v2^dagger G2 v2 ) + # therefore, to test, we calculate + # maybe_conjugate( v^dagger G v ) + # for all degenerate shells and check that they are all equal + normalized_gfs = [] + for key in d: + normalized_gf = G_new[0][key].copy() + normalized_gf.from_L_G_R(d[key][0].conjugate().transpose(), G_new[0][key], d[key][0]) + if d[key][1]: + conjugate_in_tau(normalized_gf, in_place=True) + normalized_gfs.append(normalized_gf) + for i in range(len(normalized_gfs)): + for j in range(i+1,len(normalized_gfs)): + assert_gfs_are_close(normalized_gfs[i], normalized_gfs[j]) diff --git a/test/analyze_block_structure_from_gf.ref.h5 b/test/analyze_block_structure_from_gf.ref.h5 new file mode 100644 index 0000000000000000000000000000000000000000..7acea34d680aa13c55ebfa786da8eea4044c2812 GIT binary patch literal 73312 zcmeHQ4RjpUbskCJEaq=9f5L&VHc*z7HjA-gNsr})7_xv1i*1T9B|H8RUclhRl8ur> zTS1c34J}~c(CCmr6mn>{9NMa+6t%^+pg=aHX%$KuL1-%oC2IPEAW2cu5;|}1{bpyb zb~LlvS&g)s@v+{!@7{Osd-uI}@B5qCFQnIAbok<>i#7E`BHBS(v>e5s5BSkP(o#+W z47|<}!fIN9;bJRAS~T@f)7m-xDCRHeHm<+$Ld~EAe}tS(8#|a{_R;|xhRv>l^o8eV zR2@6HqUcX0?q{g~mhQ94(JkF8$|3q?3IsKVEn1tc|3=ibmr&Qf73L=v|Nqy zL-OX(0Q&DBSErZ5&KoJ>)X#Fa5ng9{C%R&vosP-14VPWMwnb~zBAgIwqX@=Dn&F(V zuOm0x>5BIgoVlABEwBK7OX}+|EmhV;i*~%BB<4#KhuAfcU=aN=ZAaG(k)2s&_PYZ6NAMqHc!bLV|J}(21YIA)152m~C}(;p z!Jtc?NpR<{QkbGZYu70Px?y&>V>eKGhUp4y??9LS3?U|ZDCBHfZa2Z88@Yq&K1ZS7 ze_>~&zGiA?GN10r?Yw#2_1!&J?b@7owlkAQQcZNO5ZM{caX#*My+eNUO9Rr*z~6MT z|3PgqZZPhUKGTrwOp9q}CfGkhPWxfRIVs99Q+dsr4|YcCtI>9*{bg|Mm+d7m4EbHA_7kZA?_!C@bZ(tst3xibYO**F08Q9i4|75vBFA6R#?sTtgwn( zVRh7Gh1C+-3acfuRlkP|yjnV2>DAVd6;^X_D}0oI)zsXIS5pBie2jqA6v2vDOFk>i zL*7W8SY!OD;hBT7Vv?ty%{e zYXc9xWaK}fl`c{F*WCGLng5z|FS$zbU$f})(Sw%kdwb0f_m;kR+Q#8ETJr3ZuKtV7 ztF<$Ka>%teZ(FTB{kO5!?Vnw(rEY)tm4iODdh}nv_OTP5I<;ft-K5dE7!bu|EE?z`fIPfeC^Y3uNnNtjjz0O{qUME zkB{8_+7GsNJaXBS$G*38V@LGm7ax86m|OQ>bmXVsUv}wT9nXDpU-oJPUi(|$-Td#D z+|{A&xoE?2UpM4y_kaJ$AFo}#|GClDuYR|yV`AN!uYBp=^Y?%7R{v`T{{uVsz4hM2 z^}`3=|3vJ)lZSVAytn$k6CQeJQ^&5qfBPFt4fw4e-2Boh1`LDZYFW_jkO5XhS~%;- z!Y;SU>y~dOmhl7>%18dzk*A!h6;_i*D}17WPZID)1bni9V**|#;N=27#el8)Rg+RH ze3}6(YX{5wO9DP!z;OYeAz(GhwetIA0jom@EB;pmtR_EJ{KpKqIiD8o;BpVoarH1` zL$7Z$?oFt8)No$Pe`#8({P$o3Qt7R&t!2^(-xO+VNvqCfJVZ@#O$wQNUk1`++09% z^8v~24M=WZKynM7vY-X&NuDwUvxt#o;*|@={AnGJGC~Wut7wI~n#X zzcj4Qiyu za);#2p#jfWoqzQ51Waf3x!IXc?l91)-1v@`IpqnOw;L)aOZAB^)< ztpb@|p8Mx{VFAAV3=fHN%urm@W`muP`l`jwsB;dZ?$BL7O@F~1V{Rlp-1A(#Ig;MEzKdIbJl;MK0JdIUZRJYO@F`162QXKLz^dR1p@ z>JfZRy{a}J?{w0&nUSc24RQCm}K&*8&7TQ{Q|IMwZ9aH!p@I-qg1`@lcQ8Z`Mbh zfT%~{&HAVl5%mbX*ZC@v z;JHQA36FZF;JHPxytUy~{W(8QfTrNh7A5|8UzDKmZ>WJ#1EB^&4TKs9H4thb)Ig|# z={10J!90^qy^qsg-a9zK*cec2O7)-i2xw(pxtBx9m3uk;yd=U(lmt}2ms8n~9{nU2 z#32B;fs2U%`xPaI$1ior*yPDh`^7r%+v{9^xA!-azfOcPrk_|(kqpCO(A*lpe(@kz z6X&ui?gvi&EPWMa&^ezIUEvx#9g}O==al2PmVHjOX9jyP^?L?>-#aXNy8j^W9S-w& zM7?DQ`_^}v#Moi%Z%w+;#W-93a(n*y2Ek9|xZqR$RIT?$2R*f)|8j={k~|5J7{&yc(il;Cv` z_!fEnSQ6#%EMS2U!hT47)nY%?-4W_5;Uxzrd+^ z!ENwbqCmYy8J^5K5Pm$eRUiZyW4O<3P|*iY0ezYR659ws??+=VX1bb42HK1jv>#Hb5hhBKsL zK*6BFq5t+XYR#;ML7xX85{@1=;-I?d z{N8}&7Xp^wAF%wQC;9L*ojg=9>Z7~uV<*8N{6M|)K_|bI`#cHK?cz``rwi?_)D;zOBo!`Mx#7=KIwQo9|OIY`!1Pu=zeX z?9C7gJWoQmeHi_Bs3MVhQlGGx{%Qd01Nl3P^{o#ozdzvC{|dK<{mefDEE_7^5S%}-=MiLkv| zSgl-tZQcBU&J*Qu9#X%q=OYIvKM>`0IO^p0`XBa7{(f|Q_DjxxobUS;?xdO}xq^Lr zDT4JN>K%s7sR8tRdA^dqkLv5RKb3x%@H(r-iLUU7osP+;oUau59L1df@VFcQUE~PE zY8rt3C<%SlXFq0R{uAL(;9;kgYUg&o5@CB)O&2Pyoe?9y=R`s2aYko;e|kFD#Ss^} z>A3`tZQMRvyQg++ocwse@{<9}PX{c&)02GonL!>3y&UfSDMg(8$G{@;2s+a{(Ty#( z(=oa6-b-8g-51z}X!(ma#_v2mNEF};dW4PZuQ^ZpYMlJufaMoF$(QFVnY++3)x%Cs z9&w?|A^SauR1eWV`&{UF*{EqeZ?4Ww)A|`vy4Q)KG3kx#NBy4K5w+s;4D3>h4`#8oy82;`saU z+CwBSGC$Q9mby+2VBQD+jMZKa4w3mMIK=utU8h{kAJFeg-0#6Z{s$x=&E;rkc_V*D z5ztLC-2Mcmqnxo9>~v{{b0tboQJ`ghWT%^am*94u_hy(bFUr?<5S1YQ0TJYwZh&Ew zuW&fUibo=a34ID+Kcv29YCq(6+T8qC>Z?={w4+be3fasP4LI44;+O3ez_`RHNZZjh zLsQP(3d92ZbG&{mh;q~{sL3Sr`R@edyoa{`7{SVZEc?#Zt_s7muzNbFU=dIuy{TfM52tQc*V@e0z1jEtCQPPDK z!p=y2)naFkG*kwCI(=trFRQghi56T`}P`HQ?yTVe?mR6l2}^rH;hGg~GL06UlDeq%u`=qUEv`&bK8-(!o@d6e-3 zX{tS=Mq^SBh-ep`ziz{YM%u>pSE`_laBkQ9$z>YOO>s?=?do*?Rp4>1b4EA+*8e9& zh<1m(FkBcKaPn^n;V=C5Z?MbKKlx{uBjph^z|GjACCjmvw(54-7`Ej{+G(WYe0l6o ziB6}${OdfPZ{hL0mjrVT>v-OE#{-*aT~V>q<3j(YAdX{ z{zbHGcI(cYj33eM&1TCgQ+6AESS6s*Dj~g>-dCnpc%lZr&G7#!-d?vKXjw)gz?mRx zzj@*I2R1qRfxW!1ty4DF^PIsaiI8f;nZjVfXh8Y_*q0>tBParX0KGB|#0*3D0eK!% ziyt_`kd5-la|oyLG5MENV4chDHcx8*Ya)bRI9nJj5Dm!jf&Io#wwq8xqxTypcs!!N zw||`^Cq+3>o-ia0z|Kg0)n{ki_Z#)UA^AEtgqxj7K23yirVoRKr2%PY;BSZj%B}~b zW500)qtE7WC5NyRZv9EFKRTZx2FTyX@Bo(seo#MPrz_g>PuT$3_wSF(Tbs4dW*jh@iGpK*4RW3clY}ag=ECBjP-#$xXl_>n^qzhe)^XB(g zVPZ)_KOc9Yvt*gosQ>M^*i-xYFLy~ma+d}qcezKo)z2Mc&r&zjxwpB^116as{drb9 zX(%jk4LHpMO3&Df=Jz}R{!9Atx$D0^>SO7-9M_ zSXdg6;{$fG_$|90Fg`FY(sp#sklg1Yj@T6dJA?gX*n^av%riuG2D_7* zR%HJOz9S4z{DWtf3z86aM(V2;JLBd4YM!-=7DGGXKFtY6g0dm%KjCQRQn~j;$(8%5 z>z5Hrm80@h-&d~Ody2BXs^qZ8z-{y&DIMk1UM4uke#)M!`5~u!4*jeTomD{o!uh*# z`R@^7jOpY5Opy%3VbI(ffWH{zYIbti`x-@@`dQ!Wgx8tgiEjAc>~u_S{!XkM$FF)v2y}g`SKC)l1A8m$ZQ*n9!uVUZi{rfG;h!yccJ*wNc%J0NZy4WY!x1mvRtRBLT zCtj(JM{0~CMHf2I&(+ZX{l6PLwV(fTcLgN(GXcrHBOtkV1|;{sfaE?HklaT+$%S1> za0KfNr+X`_nC=`7&*d=5;dvaka0oxeVBG<&Ul#G(T$&bpb$XVlSHBA#${+py^!!qc zF1XO8!G`@aKpAE@ANMi?_ARW=DDyNn0Lir zx0e*-8g|AUZ+0@z5Z3c@|J1K}u3Nt!c#DdP`g$&SNZ1q_ko~@$YZYUAh)Sa0!%w6C zr$A6+DE9+%ybc22F^oG=jvB=@Jvr=$)K@L`BbfcbCzes;*ey@>^>SrDFvj-EsbRrw z{D(w={uCW2IKkg(bIRYW=}!AEMb?MT6?fYY?E4QQj4^%k9g1Wa4uj^_0Q|)uR}=H4 z!UQEa^|RFf5MJkePIP@gx6?7XxgRLUaV>UkcJ~9HW&37dQB=2YmHog7k1y0)hOlp? z|CAUz3_qUwFMGO#Vw^DKLMQXhHQ4`k<%^!$&wsfu1tj;?faJarklY^yB=_Bb<1?P8#SmNqFzN8x+G_hy6L{x4qXkRu>`nxuXHhb1}b-a?z4MwU-g&x`mT5-t1Jh zL)*HxXS;J(jscj7xZ)0nb1J z+}8JFyuabpyzPuA{+|;CrN*Ps)Q*jlzan7y7X&PS zeZca!c#;o4)5${tqdxtCeQYEcWOt<1J0EoNU$N-){;P5Qb(bf7HBSB=0n5M7lYHD4 zLi@*mVecmrLcc1y(B(MesOWc+UoR(g(lvaEHsJ!tMqTLonQnl;V{I~MaHMhl=n+rt zi0Y}|G0Y}TKQqR^Y-qy#%Z4Vr;*4?@6FytOD=qL@f}et|{1j~Er(i2T1v5X`n;{f< zo`i1uF#U&6%_8%pK4CHa)d1E9@^{keTOU-upXJv7h7YCw2Y>Hx?LuyIT?2C7*Ukk_ zv0Xy>8~vTn{<}#M?7a3Nip4}ZP@XU(4Zwa#ebr|_W@CTh2~YDAnrBw-N2S)M~CyEh1Msn^_6}I&DL`pip9awH<@t_w67_>d)mWbIj7^dxNbTeOw}B-{X;ew( zH(%HfsjvF%$85~MUh?F(sh?EtZw~XhqEoA3{ZKe=`hF8<29e{Zr-NNAxX?M3XRf3- zZvOR#r*>?d{C5ME-+BtQF=h+|$#cra)qhFA@|Sy(KUcLn!b( G3I87l#o5RJ literal 0 HcmV?d00001 From 318c5a36e70946e778f893b1009a7e90602fab57 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Wed, 28 Feb 2018 12:58:43 +0100 Subject: [PATCH 28/44] SumkDFT: adapt symm_deg_gf to work with the new deg_shells --- python/sumk_dft.py | 50 +++++++++++++++++++---- test/analyze_block_structure_from_gf.py | 53 ++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 3d3b1f30..64d5265c 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1575,20 +1575,56 @@ class SumkDFT(object): Parameters ---------- gf_to_symm : gf_struct_solver like - Input GF. + Input and output GF (i.e., it gets overwritten) orb : int Index of an inequivalent shell. """ + # when reading block_structures written with older versions from + # an h5 file, self.deg_shells might be None + if self.deg_shells is None: return + for degsh in self.deg_shells[orb]: - ss = gf_to_symm[degsh[0]].copy() - ss.zero() + # ss will hold the averaged orbitals in the basis where the + # blocks are all equal + # i.e. maybe_conjugate(v^dagger gf v) + ss = None n_deg = len(degsh) - for bl in degsh: - ss += gf_to_symm[bl] / (1.0 * n_deg) - for bl in degsh: - gf_to_symm[bl] << ss + for key in degsh: + if ss is None: + ss = gf_to_symm[key].copy() + ss.zero() + helper = ss.copy() + # get the transformation matrix + if isinstance(degsh, dict): + v, C = degsh[key] + else: + # for backward compatibility, allow degsh to be a list + v = numpy.eye(*ss.target_shape) + C = False + # the helper is in the basis where the blocks are all equal + helper.from_L_G_R(v.conjugate().transpose(), gf_to_symm[key], v) + if C: + conjugate_in_tau(helper, in_place=True) + # average over all shells + ss += helper / (1.0 * n_deg) + # now put back the averaged gf to all shells + for key in degsh: + if isinstance(degsh, dict): + v, C = degsh[key] + else: + # for backward compatibility, allow degsh to be a list + v = numpy.eye(*ss.target_shape) + C = False + if C: + # we could also use + # gf_to_symm[key].from_L_G_R(v, conjugate_in_tau(ss), v.conjugate().transpose()) + # but this is less memory-intensive: + gf_to_symm[key].from_L_G_R(v.conjugate(), ss, v.transpose()) + conjugate_in_tau(gf_to_symm[key], in_place=True) + else: + gf_to_symm[key].from_L_G_R(v, ss, v.conjugate().transpose()) def total_density(self, mu=None, iw_or_w="iw", with_Sigma=True, with_dc=True, broadening=None): r""" diff --git a/test/analyze_block_structure_from_gf.py b/test/analyze_block_structure_from_gf.py index cda63295..94ec6e18 100644 --- a/test/analyze_block_structure_from_gf.py +++ b/test/analyze_block_structure_from_gf.py @@ -2,7 +2,7 @@ from pytriqs.gf import * from sumk_dft import SumkDFT, conjugate_in_tau from scipy.linalg import expm import numpy as np -from pytriqs.utility.comparison_tests import assert_gfs_are_close, assert_arrays_are_close +from pytriqs.utility.comparison_tests import assert_gfs_are_close, assert_arrays_are_close, assert_block_gfs_are_close from pytriqs.archive import * import itertools @@ -138,17 +138,41 @@ for conjugate in conjugate_values: G[0]['ud'][i:i+2,i:i+2] << inverse(Omega-delta) G[0]['ud'] << inverse(inverse(G[0]['ud']) - Hloc) + # for testing symm_deg_gf below, we need this + # we construct it so that for every group of degenerate blocks of G[0], the + # mean of the blocks of G_noisy is equal to G[0] + G_noisy = G[0].copy() + noise1 = np.random.randn(*delta.target_shape) + G_noisy['ud'][:2,:2].data[:,:,:] += noise1 + G_noisy['ud'][2:4,2:4].data[:,:,:] -= noise1/2.0 + G_noisy['ud'][4:6,4:6].data[:,:,:] -= noise1/2.0 + noise2 = np.random.randn(*delta.target_shape) + G_noisy['ud'][6:8,6:8].data[:,:,:] += noise2 + G_noisy['ud'][8:,8:].data[:,:,:] -= noise2 + + # for testing backward-compatibility in symm_deg_gf, we need the + # un-transformed Green's functions + G_pre_transform = G[0].copy() + G_noisy_pre_transform = G_noisy.copy() + # transform each block using a random transformation matrix for i in range(0,10,2): T = get_random_transformation(2) G[0]['ud'][i:i+2,i:i+2].from_L_G_R(T, G[0]['ud'][i:i+2,i:i+2], T.conjugate().transpose()) + G_noisy['ud'][i:i+2,i:i+2].from_L_G_R(T, G_noisy['ud'][i:i+2,i:i+2], T.conjugate().transpose()) # if that block shall be conjugated, go ahead and do it if conjugate[i//2]: conjugate_in_tau(G[0]['ud'][i:i+2,i:i+2], in_place=True) + conjugate_in_tau(G_noisy['ud'][i:i+2,i:i+2], in_place=True) # analyse the block structure G_new = SK.analyse_block_structure_from_gf(G) + # transform G_noisy etc. to the new block structure + G_noisy = SK.block_structure.convert_gf(G_noisy, block_structure1, beta = G_noisy.mesh.beta) + G_pre_transform = SK.block_structure.convert_gf(G_pre_transform, block_structure1, beta = G_noisy.mesh.beta) + G_noisy_pre_transform = SK.block_structure.convert_gf(G_noisy_pre_transform, block_structure1, beta = G_noisy.mesh.beta) + assert len(SK.deg_shells[0]) == 2, "wrong number of equivalent groups found" assert sorted([len(d) for d in SK.deg_shells[0]]) == [2,3], "wrong number of members in the equivalent groups found" for d in SK.deg_shells[0]: @@ -177,3 +201,30 @@ for conjugate in conjugate_values: for i in range(len(normalized_gfs)): for j in range(i+1,len(normalized_gfs)): assert_gfs_are_close(normalized_gfs[i], normalized_gfs[j]) + + # now we check symm_deg_gf + # symmetrizing the GF as is has to leave it unchanged + G_new_symm = G_new[0].copy() + SK.symm_deg_gf(G_new_symm, 0) + assert_block_gfs_are_close(G_new[0], G_new_symm) + + # symmetrizing the noisy GF, which was carefully constructed, + # has to give the same result as G_new[0] + SK.symm_deg_gf(G_noisy, 0) + assert_block_gfs_are_close(G_new[0], G_noisy) + + # check backward compatibility of symm_deg_gf + # first, construct the old format of the deg shells + for ish in range(len(SK.deg_shells)): + for gr in range(len(SK.deg_shells[ish])): + SK.deg_shells[ish][gr] = SK.deg_shells[ish][gr].keys() + + # symmetrizing the GF as is has to leave it unchanged + G_new_symm << G_pre_transform + SK.symm_deg_gf(G_new_symm, 0) + assert_block_gfs_are_close(G_new_symm, G_pre_transform) + + # symmetrizing the noisy GF pre transform, which was carefully constructed, + # has to give the same result as G_pre_transform + SK.symm_deg_gf(G_noisy_pre_transform, 0) + assert_block_gfs_are_close(G_noisy_pre_transform, G_pre_transform) From a63169e45fbc69f037cae14a685f89e960b15ae9 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Thu, 1 Mar 2018 16:09:24 +0100 Subject: [PATCH 29/44] SumkDFT: check the supplied gf for every shell in analyse_block_structure_from_gf and analyse_deg_shells --- python/sumk_dft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 64d5265c..33fb8b23 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -884,7 +884,7 @@ class SumkDFT(object): """ # make a GfImTime from the supplied G - if isinstance(G[0]._first(), GfImFreq): + if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) for g_sh in G] @@ -892,7 +892,7 @@ class SumkDFT(object): for name, g in gf[ish]: g.set_from_inverse_fourier(G[ish][name]) else: - assert isinstance(G[0]._first(), GfImTime), "G must be a BlockGf of either GfImFreq or GfImTime" + assert all(isinstance(g_sh._first(), GfImTime) for g_sh in G), "G must be a BlockGf of either GfImFreq or GfImTime" gf = G # initialize the variables @@ -1003,7 +1003,7 @@ class SumkDFT(object): return null_space.conjugate().transpose() # make a GfImTime from the supplied G - if isinstance(G[0]._first(), GfImFreq): + if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) for g_sh in G] @@ -1011,7 +1011,7 @@ class SumkDFT(object): for name, g in gf[ish]: g.set_from_inverse_fourier(G[ish][name]) else: - assert isinstance(G[0]._first(), GfImTime), "G must be a BlockGf of either GfImFreq or GfImTime" + assert all(isinstance(g_sh._first(), GfImTime) for g_sh in G), "G must be a BlockGf of either GfImFreq or GfImTime" gf = G if include_shells is None: From c85bed04891d5b2ba26f6dabf8d49d71b63ae64b Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Wed, 7 Mar 2018 15:18:36 -0500 Subject: [PATCH 30/44] [doc] Link doc files from sources to build dir Copied from triqs build; needed for separate compilation --- doc/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 01597803..ef5ee2f3 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,6 +1,9 @@ # generate the conf.py configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) +set(EXT_FOR_DOC "rst png txt css_t conf css js gif jpg py html bib sh") +execute_process(COMMAND cp_rs ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${EXT_FOR_DOC}) + # --------------------------------- # Top Sphinx target # --------------------------------- From 73d37c68369c5bde0334f4c40ea9c660cbbc882b Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Wed, 7 Mar 2018 15:27:16 -0500 Subject: [PATCH 31/44] [jenkins] Build docs during ubuntu-clang build and publish; copied from triqs docs build, but with different BUILD_DOC cmake option. --- Dockerfile | 3 +- Jenkinsfile | 121 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/Dockerfile b/Dockerfile index 704e29a7..299f2e60 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,7 @@ COPY . ${SRC}/dft_tools WORKDIR ${BUILD}/dft_tools RUN chown build . USER build -RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} && make -j2 && make test +ARG BUILD_DOC=0 +RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} -DBUILD_DOC=${BUILD_DOC} && make -j2 && make test USER root RUN make install diff --git a/Jenkinsfile b/Jenkinsfile index fbfa59bc..d57884a3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,7 @@ +def projectName = "dft_tools" def triqsBranch = env.CHANGE_TARGET ?: env.BRANCH_NAME def triqsProject = '/TRIQS/triqs/' + triqsBranch.replaceAll('/', '%2F') +def documentationPlatform = "ubuntu-clang" properties([ disableConcurrentBuilds(), @@ -17,21 +19,21 @@ def platforms = [:] def dockerPlatforms = ["ubuntu-clang", "ubuntu-gcc", "centos-gcc"] for (int i = 0; i < dockerPlatforms.size(); i++) { def platform = dockerPlatforms[i] - platforms[platform] = { -> stage(platform) { - timeout(time: 1, unit: 'HOURS') { - node('docker') { - checkout scm - /* construct a Dockerfile for this base */ - sh """ - ( echo "FROM flatironinstitute/triqs:${triqsBranch}-${env.STAGE_NAME}" ; sed '0,/^FROM /d' Dockerfile ) > Dockerfile.jenkins - mv -f Dockerfile.jenkins Dockerfile - """ - /* build and tag */ - def img = docker.build("flatironinstitute/dft_tools:${env.BRANCH_NAME}-${env.STAGE_NAME}") - /* but we don't need the tag so clean it up (alternatively, could refacter to run in container) */ + platforms[platform] = { -> node('docker') { + stage(platform) { timeout(time: 1, unit: 'HOURS') { + checkout scm + /* construct a Dockerfile for this base */ + sh """ + ( echo "FROM flatironinstitute/triqs:${triqsBranch}-${env.STAGE_NAME}" ; sed '0,/^FROM /d' Dockerfile ) > Dockerfile.jenkins + mv -f Dockerfile.jenkins Dockerfile + """ + /* build and tag */ + def img = docker.build("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${env.STAGE_NAME}", "--build-arg BUILD_DOC=${platform==documentationPlatform} .") + if (env.BRANCH_NAME.startsWith("PR-") || platform != documentationPlatform) { + /* but we don't need the tag so clean it up (except for documentation) */ sh "docker rmi ${img.imageName()}" } - } + } } } } } @@ -42,51 +44,70 @@ def osxPlatforms = [ for (int i = 0; i < osxPlatforms.size(); i++) { def platformEnv = osxPlatforms[i] def platform = platformEnv[0] - platforms["osx-$platform"] = { -> stage("osx-$platform") { - timeout(time: 1, unit: 'HOURS') { - node('osx && triqs') { - def srcDir = pwd() - def tmpDir = pwd(tmp:true) - def buildDir = "$tmpDir/build" - def installDir = "$tmpDir/install" + platforms["osx-$platform"] = { -> node('osx && triqs') { + stage("osx-$platform") { timeout(time: 1, unit: 'HOURS') { + def srcDir = pwd() + def tmpDir = pwd(tmp:true) + def buildDir = "$tmpDir/build" + def installDir = "$tmpDir/install" - dir(installDir) { - deleteDir() - } - - copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") - unzip(zipFile: "osx-${platform}.zip", dir: installDir) - /* fixup zip-stripped permissions (JENKINS-13128) */ - sh "chmod +x $installDir/bin/*" - - checkout scm - - dir(buildDir) { withEnv(platformEnv[1]+[ - "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", - "CPATH=$installDir/include", - "LIBRARY_PATH=$installDir/lib", - "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { - deleteDir() - sh "cmake $srcDir -DTRIQS_ROOT=$installDir" - sh "make -j2" - try { - sh "make test" - } catch (exc) { - archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log') - throw exc - } - sh "make install" - } } - // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) + dir(installDir) { + deleteDir() } - } + + copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") + unzip(zipFile: "osx-${platform}.zip", dir: installDir) + /* fixup zip-stripped permissions (JENKINS-13128) */ + sh "chmod +x $installDir/bin/*" + + checkout scm + + dir(buildDir) { withEnv(platformEnv[1]+[ + "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", + "CPATH=$installDir/include", + "LIBRARY_PATH=$installDir/lib", + "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { + deleteDir() + sh "cmake $srcDir -DTRIQS_ROOT=$installDir" + sh "make -j2" + try { + sh "make test" + } catch (exc) { + archiveArtifacts(artifacts: 'Testing/Temporary/LastTest.log') + throw exc + } + sh "make install" + } } + // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) + } } } } } try { parallel platforms + if (!env.BRANCH_NAME.startsWith("PR-")) { + node("docker") { + stage("documentation") { timeout(time: 1, unit: 'HOURS') { + def workDir = pwd() + dir("$workDir/gh-pages") { + def subdir = env.BRANCH_NAME + git(url: "ssh://git@github.com/TRIQS/${projectName}.git", branch: "gh-pages", credentialsId: "ssh", changelog: false) + sh "rm -rf ${subdir}" + docker.image("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${documentationPlatform}").inside() { + sh "cp -rp \$INSTALL/share/doc/${projectName} ${subdir}" + } + sh "git add -A ${subdir}" + sh """ + git commit --author='Flatiron Jenkins ' --allow-empty -m 'Generated documentation for ${env.BRANCH_NAME}' -m "`git --git-dir ${workDir}/.git rev-parse HEAD`" + """ + // note: credentials used above don't work (need JENKINS-28335) + sh "git push origin gh-pages" + } + } } + } + } } catch (err) { - emailext( + if (env.BRANCH_NAME != "jenkins") emailext( subject: "\$PROJECT_NAME - Build # \$BUILD_NUMBER - FAILED", body: """\$PROJECT_NAME - Build # \$BUILD_NUMBER - FAILED From a89d558cd6c1e9e81fd40b95bd52bbd0f7c4954b Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Tue, 13 Mar 2018 13:23:52 +0100 Subject: [PATCH 32/44] [doc] Run sphinx against source dir, change option BUILD_DOC -> Build_Documentation --- CMakeLists.txt | 6 +++--- doc/CMakeLists.txt | 5 +---- doc/install.rst | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc0b81a..a0e35fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,10 +58,10 @@ endif() #------------------------ # Documentation #------------------------ -option(BUILD_DOC "Build documentation" OFF) -if(${BUILD_DOC}) +option(Build_Documentation "Build documentation" OFF) +if(${Build_Documentation}) if(NOT ${TRIQS_WITH_DOCUMENTATION}) message("Error: TRIQS library has not been compiled with its documentation") endif() add_subdirectory(doc) -endif(${BUILD_DOC}) +endif() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index ef5ee2f3..d7490167 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,9 +1,6 @@ # generate the conf.py configure_file(${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py @ONLY) -set(EXT_FOR_DOC "rst png txt css_t conf css js gif jpg py html bib sh") -execute_process(COMMAND cp_rs ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${EXT_FOR_DOC}) - # --------------------------------- # Top Sphinx target # --------------------------------- @@ -13,7 +10,7 @@ file(GLOB_RECURSE sources *.rst) # create documentation target set(sphinx_top ${CMAKE_CURRENT_BINARY_DIR}/html/index.html) add_custom_command(OUTPUT ${sphinx_top} DEPENDS ${sources} - COMMAND ${TRIQS_SPHINXBUILD_EXECUTABLE} -c . -j8 -b html ${CMAKE_CURRENT_BINARY_DIR} html) + COMMAND ${TRIQS_SPHINXBUILD_EXECUTABLE} -c . -j8 -b html ${CMAKE_CURRENT_SOURCE_DIR} html) add_custom_target(doc_sphinx ALL DEPENDS ${sphinx_top} ${CMAKE_CURRENT_BINARY_DIR}) # --------------------------------- diff --git a/doc/install.rst b/doc/install.rst index d8184744..a9dbf263 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -83,7 +83,7 @@ Finally, you will have to change the calls to :program:`python_with_DMFT` to Version compatibility ---------------------- +--------------------- Be careful that the version of the TRIQS library and of the dft tools must be compatible (more information on the :ref:`TRIQS website `. @@ -97,3 +97,18 @@ Checkout the version of the code that you want, for instance:: $ git co 1.2 Then follow the steps 2 to 5 described above to compile the code. + +Custom CMake options +-------------------- + +Functionality of ``dft_tools`` can be tweaked using extra compile-time options passed to CMake:: + + cmake -DOPTION1=value1 -DOPTION2=value2 ... ../cthyb.src + ++---------------------------------------------------------------+-----------------------------------------------+ +| Options | Syntax | ++===============================================================+===============================================+ +| Disable testing (not recommended) | -DBuild_Tests=OFF | ++---------------------------------------------------------------+-----------------------------------------------+ +| Build the documentation locally | -DBuild_Documentation=ON | ++---------------------------------------------------------------+-----------------------------------------------+ From dae191720c4b1b31dd4e58bc01819bfebcb403ec Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Tue, 13 Mar 2018 13:29:43 +0100 Subject: [PATCH 33/44] [doc] Updating jenkins and dockerfile after previous commit --- Dockerfile | 4 ++-- Jenkinsfile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 299f2e60..6b28ea52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ COPY . ${SRC}/dft_tools WORKDIR ${BUILD}/dft_tools RUN chown build . USER build -ARG BUILD_DOC=0 -RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} -DBUILD_DOC=${BUILD_DOC} && make -j2 && make test +ARG Build_Documentation=0 +RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} -DBuild_Documentation=${Build_Documentation} && make -j2 && make test USER root RUN make install diff --git a/Jenkinsfile b/Jenkinsfile index d57884a3..9274b8d0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -28,7 +28,7 @@ for (int i = 0; i < dockerPlatforms.size(); i++) { mv -f Dockerfile.jenkins Dockerfile """ /* build and tag */ - def img = docker.build("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${env.STAGE_NAME}", "--build-arg BUILD_DOC=${platform==documentationPlatform} .") + def img = docker.build("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${env.STAGE_NAME}", "--build-arg Build_Documentation=${platform==documentationPlatform} .") if (env.BRANCH_NAME.startsWith("PR-") || platform != documentationPlatform) { /* but we don't need the tag so clean it up (except for documentation) */ sh "docker rmi ${img.imageName()}" From 8d6d8b53c5b73c1033a6f7b5e742b650982a7981 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Mon, 19 Mar 2018 11:09:31 +0100 Subject: [PATCH 34/44] SumkDFT: analyze_block_structure_from_gf for Gf Re/Im Time/Freq --- python/sumk_dft.py | 114 ++++++++++++---------- test/CMakeLists.txt | 2 +- test/analyze_block_structure_from_gf.py | 10 +- test/analyze_block_structure_from_gf2.py | 115 +++++++++++++++++++++++ 4 files changed, 187 insertions(+), 54 deletions(-) create mode 100644 test/analyze_block_structure_from_gf2.py diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 33fb8b23..7f527441 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -883,7 +883,7 @@ class SumkDFT(object): the Green's function transformed into the new block structure """ - # make a GfImTime from the supplied G + # make a GfImTime from the supplied GfImFreq if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) @@ -891,9 +891,37 @@ class SumkDFT(object): for ish in range(len(gf)): for name, g in gf[ish]: g.set_from_inverse_fourier(G[ish][name]) - else: - assert all(isinstance(g_sh._first(), GfImTime) for g_sh in G), "G must be a BlockGf of either GfImFreq or GfImTime" + # keep a GfImTime from the supplied GfImTime + elif all(isinstance(g_sh._first(), GfImTime) for g_sh in G): gf = G + # make a spectral function from the supplied GfReFreq + elif all(isinstance(g_sh._first(), GfReFreq) for g_sh in G): + gf = [g_sh.copy() for g_sh in G] + for ish in range(len(gf)): + for name, g in gf[ish]: + g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi + elif all(isinstance(g_sh._first(), GfReTime) for g_sh in G): + def get_delta_from_mesh(mesh): + w0 = None + for w in mesh: + if w0 is None: + w0 = w + else: + return w-w0 + gf = [BlockGf( + name_block_generator = [(name, + GfReFreq( + window=(-numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), + n_points=len(block.mesh), + indices=block.indices)) for name, block in g_sh]) + for g_sh in G] + + for ish in range(len(gf)): + for name, g in gf[ish]: + g.set_from_fourier(G[ish][name]) + g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi + else: + raise Exception("G must be a list of BlockGf of either GfImFreq, GfImTime, GfReFreq or GfReTime") # initialize the variables self.gf_struct_solver = [{} for ish in range(self.n_inequiv_shells)] @@ -964,7 +992,8 @@ class SumkDFT(object): for ish in range(self.n_inequiv_shells)],None) G_transformed = [ self.block_structure.convert_gf(G[ish], - full_structure, ish, beta=G[ish].mesh.beta, show_warnings=threshold) + full_structure, ish, mesh=G[ish].mesh.copy(), show_warnings=threshold, + gf_function=type(G[ish]._first())) for ish in range(self.n_inequiv_shells)] if analyse_deg_shells: @@ -1002,7 +1031,7 @@ class SumkDFT(object): null_space = compress(null_mask, vh, axis=0) return null_space.conjugate().transpose() - # make a GfImTime from the supplied G + # make a GfImTime from the supplied GfImFreq if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) @@ -1010,9 +1039,37 @@ class SumkDFT(object): for ish in range(len(gf)): for name, g in gf[ish]: g.set_from_inverse_fourier(G[ish][name]) - else: - assert all(isinstance(g_sh._first(), GfImTime) for g_sh in G), "G must be a BlockGf of either GfImFreq or GfImTime" + # keep a GfImTime from the supplied GfImTime + elif all(isinstance(g_sh._first(), GfImTime) for g_sh in G): gf = G + # make a spectral function from the supplied GfReFreq + elif all(isinstance(g_sh._first(), GfReFreq) for g_sh in G): + gf = [g_sh.copy() for g_sh in G] + for ish in range(len(gf)): + for name, g in gf[ish]: + g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi + elif all(isinstance(g_sh._first(), GfReTime) for g_sh in G): + def get_delta_from_mesh(mesh): + w0 = None + for w in mesh: + if w0 is None: + w0 = w + else: + return w-w0 + gf = [BlockGf( + name_block_generator = [(name, + GfReFreq( + window=(-numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), + n_points=len(block.mesh), + indices=block.indices)) for name, block in g_sh]) + for g_sh in G] + + for ish in range(len(gf)): + for name, g in gf[ish]: + g.set_from_fourier(G[ish][name]) + g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi + else: + raise Exception("G must be a list of BlockGf of either GfImFreq, GfImTime, GfReFreq or GfReTime") if include_shells is None: # include all shells @@ -1606,7 +1663,7 @@ class SumkDFT(object): # the helper is in the basis where the blocks are all equal helper.from_L_G_R(v.conjugate().transpose(), gf_to_symm[key], v) if C: - conjugate_in_tau(helper, in_place=True) + helper << helper.transpose() # average over all shells ss += helper / (1.0 * n_deg) # now put back the averaged gf to all shells @@ -1618,11 +1675,7 @@ class SumkDFT(object): v = numpy.eye(*ss.target_shape) C = False if C: - # we could also use - # gf_to_symm[key].from_L_G_R(v, conjugate_in_tau(ss), v.conjugate().transpose()) - # but this is less memory-intensive: - gf_to_symm[key].from_L_G_R(v.conjugate(), ss, v.transpose()) - conjugate_in_tau(gf_to_symm[key], in_place=True) + gf_to_symm[key].from_L_G_R(v, ss.transpose(), v.conjugate().transpose()) else: gf_to_symm[key].from_L_G_R(v, ss, v.conjugate().transpose()) @@ -2015,38 +2068,3 @@ class SumkDFT(object): def __set_deg_shells(self,value): self.block_structure.deg_shells = value deg_shells = property(__get_deg_shells,__set_deg_shells) - -# a helper function -def conjugate_in_tau(gf_im_freq, in_place=False): - """ Calculate the conjugate in tau of a GfImFreq - - Parameters - ---------- - gf_im_freq : GfImFreq of BlockGf - the Green's function - in_place : whether to modify the gf_im_freq object (True) or return a copy (False) - - Returns - ------- - ret : GfImFreq of BlockGf - the Green's function that has been FT to G(tau), conjugated, and - FT back - """ - if in_place: - ret = gf_im_freq - else: - ret = gf_im_freq.copy() - if isinstance(ret, BlockGf): - for name, gf in ret: - conjugate_in_tau(gf, in_place=True) - else: - """ there is an easier way to do this, namely to make - ret.data[:,:,:] = gf_im_freq.data[::-1,:,:].conjugate() - ret.tail.data[:,:,:] = gf_im_freq.tail.data.conjugate() - but this relies on symmetric Matsubara meshes and is maybe - not safe enough""" - G_tau = GfImTime(beta=gf_im_freq.mesh.beta, - indices=gf_im_freq.indices,n_points=len(gf_im_freq.mesh)+1) - G_tau.set_from_inverse_fourier(gf_im_freq) - ret.set_from_fourier(G_tau.conjugate()) - return ret diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 02edb21a..b1dc6e8c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,7 +5,7 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${all_h5_files} DESTINATION ${CMAKE_CURREN FILE(COPY SrVO3.pmat SrVO3.struct SrVO3.outputs SrVO3.oubwin SrVO3.ctqmcout SrVO3.symqmc SrVO3.sympar SrVO3.parproj SrIrO3_rot.h5 hk_convert_hamiltonian.hk LaVO3-Pnma_hr.dat LaVO3-Pnma.inp DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # List all tests -set(all_tests wien2k_convert hk_convert w90_convert sumkdft_basic srvo3_Gloc srvo3_transp sigma_from_file blockstructure analyze_block_structure_from_gf) +set(all_tests wien2k_convert hk_convert w90_convert sumkdft_basic srvo3_Gloc srvo3_transp sigma_from_file blockstructure analyze_block_structure_from_gf analyze_block_structure_from_gf2) foreach(t ${all_tests}) add_test(NAME ${t} COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/${t}.py) diff --git a/test/analyze_block_structure_from_gf.py b/test/analyze_block_structure_from_gf.py index 94ec6e18..c777e9c3 100644 --- a/test/analyze_block_structure_from_gf.py +++ b/test/analyze_block_structure_from_gf.py @@ -1,5 +1,5 @@ from pytriqs.gf import * -from sumk_dft import SumkDFT, conjugate_in_tau +from sumk_dft import SumkDFT from scipy.linalg import expm import numpy as np from pytriqs.utility.comparison_tests import assert_gfs_are_close, assert_arrays_are_close, assert_block_gfs_are_close @@ -68,7 +68,7 @@ for d in SK.deg_shells[0]: normalized_gf = G_new[0][key].copy() normalized_gf.from_L_G_R(d[key][0].conjugate().transpose(), G_new[0][key], d[key][0]) if d[key][1]: - conjugate_in_tau(normalized_gf, in_place=True) + normalized_gf << normalized_gf.transpose() normalized_gfs.append(normalized_gf) for i in range(len(normalized_gfs)): for j in range(i+1,len(normalized_gfs)): @@ -162,8 +162,8 @@ for conjugate in conjugate_values: G_noisy['ud'][i:i+2,i:i+2].from_L_G_R(T, G_noisy['ud'][i:i+2,i:i+2], T.conjugate().transpose()) # if that block shall be conjugated, go ahead and do it if conjugate[i//2]: - conjugate_in_tau(G[0]['ud'][i:i+2,i:i+2], in_place=True) - conjugate_in_tau(G_noisy['ud'][i:i+2,i:i+2], in_place=True) + G[0]['ud'][i:i+2,i:i+2] << G[0]['ud'][i:i+2,i:i+2].transpose() + G_noisy['ud'][i:i+2,i:i+2] << G_noisy['ud'][i:i+2,i:i+2].transpose() # analyse the block structure G_new = SK.analyse_block_structure_from_gf(G) @@ -196,7 +196,7 @@ for conjugate in conjugate_values: normalized_gf = G_new[0][key].copy() normalized_gf.from_L_G_R(d[key][0].conjugate().transpose(), G_new[0][key], d[key][0]) if d[key][1]: - conjugate_in_tau(normalized_gf, in_place=True) + normalized_gf << normalized_gf.transpose() normalized_gfs.append(normalized_gf) for i in range(len(normalized_gfs)): for j in range(i+1,len(normalized_gfs)): diff --git a/test/analyze_block_structure_from_gf2.py b/test/analyze_block_structure_from_gf2.py new file mode 100644 index 00000000..d371a9c5 --- /dev/null +++ b/test/analyze_block_structure_from_gf2.py @@ -0,0 +1,115 @@ +from pytriqs.gf import * +from sumk_dft import SumkDFT +import numpy as np +from pytriqs.utility.comparison_tests import assert_block_gfs_are_close + +# here we test the SK.analyze_block_structure_from_gf function +# with GfReFreq, GfReTime + + +# helper function to get random Hermitian matrix +def get_random_hermitian(dim): + herm = np.random.rand(dim,dim)+1.0j*np.random.rand(dim,dim) + herm = herm + herm.conjugate().transpose() + return herm + +# helper function to get random unitary matrix +def get_random_transformation(dim): + herm = get_random_hermitian(dim) + T = expm(1.0j*herm) + return T + +# construct a random block-diagonal Hloc +Hloc = np.zeros((10,10), dtype=np.complex_) +# the Hloc of the first three 2x2 blocks is equal +Hloc0 = get_random_hermitian(2) +Hloc[:2,:2] = Hloc0 +Hloc[2:4,2:4] = Hloc0 +Hloc[4:6,4:6] = Hloc0 +# the Hloc of the last two 2x2 blocks is equal +Hloc1 = get_random_hermitian(2) +Hloc[6:8,6:8] = Hloc1 +Hloc[8:,8:] = Hloc1 +# construct the hybridization delta +# this is equal for all 2x2 blocks +V = get_random_hermitian(2) # the hopping elements from impurity to bath +b1 = np.random.rand() # the bath energy of the first bath level +b2 = np.random.rand() # the bath energy of the second bath level +delta = GfReFreq(window=(-5,5), indices=range(2), n_points=1001) +delta[0,0] << (V[0,0]*V[0,0].conjugate()*inverse(Omega-b1)+V[0,1]*V[0,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 +delta[0,1] << (V[0,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[0,1]*V[1,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 +delta[1,0] << (V[1,0]*V[0,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[0,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 +delta[1,1] << (V[1,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[1,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 +# construct G +G = BlockGf(name_block_generator=(('ud',GfReFreq(window=(-5,5), indices=range(10), n_points=1001)),)) +for i in range(0,10,2): + G['ud'][i:i+2,i:i+2] << inverse(Omega-delta+0.02j) +G['ud'] << inverse(inverse(G['ud']) - Hloc) + + +SK = SumkDFT(hdf_file = 'SrIrO3_rot.h5', use_dft_blocks=False) +G_new = SK.analyse_block_structure_from_gf([G]) +G_new_symm = G_new[0].copy() +SK.symm_deg_gf(G_new_symm, 0) +assert_block_gfs_are_close(G_new[0], G_new_symm) + + +assert SK.gf_struct_sumk == [[('ud', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])], [('ud', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])]],\ + "wrong gf_struct_sumk" +for i in range(5): + assert 'ud_{}'.format(i) in SK.gf_struct_solver[0], "missing block" + assert SK.gf_struct_solver[0]['ud_{}'.format(i)] == range(2), "wrong block size" +for i in range(10): + assert SK.sumk_to_solver[0]['ud',i] == ('ud_{}'.format(i/2), i%2), "wrong mapping" + +assert len(SK.deg_shells[0]) == 2, "wrong number of equivalent groups found" +assert sorted([len(d) for d in SK.deg_shells[0]]) == [2,3], "wrong number of members in the equivalent groups found" +for d in SK.deg_shells[0]: + if len(d)==2: + assert 'ud_3' in d, "shell ud_3 missing" + assert 'ud_4' in d, "shell ud_4 missing" + if len(d)==3: + assert 'ud_0' in d, "shell ud_0 missing" + assert 'ud_1' in d, "shell ud_1 missing" + assert 'ud_2' in d, "shell ud_2 missing" + + + +def get_delta_from_mesh(mesh): + w0 = None + for w in mesh: + if w0 is None: + w0 = w + else: + return w-w0 + +Gt = BlockGf(name_block_generator = [(name, + GfReTime(window=(-np.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), np.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), + n_points=len(block.mesh), + indices=block.indices)) for name, block in G]) + +Gt['ud'].set_from_inverse_fourier(G['ud']) + +G_new = SK.analyse_block_structure_from_gf([Gt]) +G_new_symm = G_new[0].copy() +SK.symm_deg_gf(G_new_symm, 0) +assert_block_gfs_are_close(G_new[0], G_new_symm) + +assert SK.gf_struct_sumk == [[('ud', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])], [('ud', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])]],\ + "wrong gf_struct_sumk" +for i in range(5): + assert 'ud_{}'.format(i) in SK.gf_struct_solver[0], "missing block" + assert SK.gf_struct_solver[0]['ud_{}'.format(i)] == range(2), "wrong block size" +for i in range(10): + assert SK.sumk_to_solver[0]['ud',i] == ('ud_{}'.format(i/2), i%2), "wrong mapping" + +assert len(SK.deg_shells[0]) == 2, "wrong number of equivalent groups found" +assert sorted([len(d) for d in SK.deg_shells[0]]) == [2,3], "wrong number of members in the equivalent groups found" +for d in SK.deg_shells[0]: + if len(d)==2: + assert 'ud_3' in d, "shell ud_3 missing" + assert 'ud_4' in d, "shell ud_4 missing" + if len(d)==3: + assert 'ud_0' in d, "shell ud_0 missing" + assert 'ud_1' in d, "shell ud_1 missing" + assert 'ud_2' in d, "shell ud_2 missing" From 6ef318d4b9c6a66239790d578827236a5578bf6c Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Fri, 23 Mar 2018 15:35:56 -0400 Subject: [PATCH 35/44] [jenkins] build osx against persistent triqs; dockerhub Also sync with app4triqs --- Dockerfile | 9 +++--- Jenkinsfile | 80 ++++++++++++++++++++++++++++------------------------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6b28ea52..55102072 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,12 @@ # See ../triqs/packaging for other options FROM flatironinstitute/triqs:master-ubuntu-clang -COPY . ${SRC}/dft_tools -WORKDIR ${BUILD}/dft_tools +ARG APPNAME=dft_tools +COPY . $SRC/$APPNAME +WORKDIR $BUILD/$APPNAME RUN chown build . USER build -ARG Build_Documentation=0 -RUN cmake ${SRC}/dft_tools -DTRIQS_ROOT=${INSTALL} -DBuild_Documentation=${Build_Documentation} && make -j2 && make test +ARG BUILD_DOC=0 +RUN cmake $SRC/$APPNAME -DTRIQS_ROOT=${INSTALL} -DBuild_Documentation=${BUILD_DOC} && make -j2 && make test USER root RUN make install diff --git a/Jenkinsfile b/Jenkinsfile index 9274b8d0..9be25fcc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,8 @@ def projectName = "dft_tools" +def documentationPlatform = "ubuntu-clang" def triqsBranch = env.CHANGE_TARGET ?: env.BRANCH_NAME def triqsProject = '/TRIQS/triqs/' + triqsBranch.replaceAll('/', '%2F') -def documentationPlatform = "ubuntu-clang" +def publish = !env.BRANCH_NAME.startsWith("PR-") properties([ disableConcurrentBuilds(), @@ -14,9 +15,11 @@ properties([ ]) ]) +/* map of all builds to run, populated below */ def platforms = [:] def dockerPlatforms = ["ubuntu-clang", "ubuntu-gcc", "centos-gcc"] +/* .each is currently broken in jenkins */ for (int i = 0; i < dockerPlatforms.size(); i++) { def platform = dockerPlatforms[i] platforms[platform] = { -> node('docker') { @@ -28,10 +31,10 @@ for (int i = 0; i < dockerPlatforms.size(); i++) { mv -f Dockerfile.jenkins Dockerfile """ /* build and tag */ - def img = docker.build("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${env.STAGE_NAME}", "--build-arg Build_Documentation=${platform==documentationPlatform} .") - if (env.BRANCH_NAME.startsWith("PR-") || platform != documentationPlatform) { + def img = docker.build("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${env.STAGE_NAME}", "--build-arg BUILD_DOC=${platform==documentationPlatform} .") + if (!publish || platform != documentationPlatform) { /* but we don't need the tag so clean it up (except for documentation) */ - sh "docker rmi ${img.imageName()}" + sh "docker rmi --no-prune ${img.imageName()}" } } } } } @@ -50,26 +53,20 @@ for (int i = 0; i < osxPlatforms.size(); i++) { def tmpDir = pwd(tmp:true) def buildDir = "$tmpDir/build" def installDir = "$tmpDir/install" - + def triqsDir = "${env.HOME}/install/triqs/${triqsBranch}/${platform}" dir(installDir) { deleteDir() } - copyArtifacts(projectName: triqsProject, selector: upstream(fallbackToLastSuccessful: true), filter: "osx-${platform}.zip") - unzip(zipFile: "osx-${platform}.zip", dir: installDir) - /* fixup zip-stripped permissions (JENKINS-13128) */ - sh "chmod +x $installDir/bin/*" - checkout scm - dir(buildDir) { withEnv(platformEnv[1]+[ - "PATH=$installDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", - "CPATH=$installDir/include", - "LIBRARY_PATH=$installDir/lib", - "CMAKE_PREFIX_PATH=$installDir/share/cmake"]) { + "PATH=$triqsDir/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin", + "CPATH=$triqsDir/include", + "LIBRARY_PATH=$triqsDir/lib", + "CMAKE_PREFIX_PATH=$triqsDir/share/cmake"]) { deleteDir() - sh "cmake $srcDir -DTRIQS_ROOT=$installDir" - sh "make -j2" + sh "cmake $srcDir -DCMAKE_INSTALL_PREFIX=$installDir -DTRIQS_ROOT=$triqsDir" + sh "make -j3" try { sh "make test" } catch (exc) { @@ -78,34 +75,43 @@ for (int i = 0; i < osxPlatforms.size(); i++) { } sh "make install" } } - // zip(zipFile: "osx-${platform}.zip", archive: true, dir: installDir) } } } } } try { parallel platforms - if (!env.BRANCH_NAME.startsWith("PR-")) { - node("docker") { - stage("documentation") { timeout(time: 1, unit: 'HOURS') { - def workDir = pwd() - dir("$workDir/gh-pages") { - def subdir = env.BRANCH_NAME - git(url: "ssh://git@github.com/TRIQS/${projectName}.git", branch: "gh-pages", credentialsId: "ssh", changelog: false) - sh "rm -rf ${subdir}" - docker.image("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${documentationPlatform}").inside() { - sh "cp -rp \$INSTALL/share/doc/${projectName} ${subdir}" - } - sh "git add -A ${subdir}" - sh """ - git commit --author='Flatiron Jenkins ' --allow-empty -m 'Generated documentation for ${env.BRANCH_NAME}' -m "`git --git-dir ${workDir}/.git rev-parse HEAD`" - """ - // note: credentials used above don't work (need JENKINS-28335) - sh "git push origin gh-pages" + if (publish) { node("docker") { + stage("publish") { timeout(time: 1, unit: 'HOURS') { + def commit = sh(returnStdout: true, script: "git rev-parse HEAD").trim() + def workDir = pwd() + dir("$workDir/gh-pages") { + def subdir = env.BRANCH_NAME + git(url: "ssh://git@github.com/TRIQS/${projectName}.git", branch: "gh-pages", credentialsId: "ssh", changelog: false) + sh "rm -rf ${subdir}" + docker.image("flatironinstitute/${projectName}:${env.BRANCH_NAME}-${documentationPlatform}").inside() { + sh "cp -rp \$INSTALL/share/doc/${projectName} ${subdir}" } + sh "git add -A ${subdir}" + sh """ + git commit --author='Flatiron Jenkins ' --allow-empty -m 'Generated documentation for ${env.BRANCH_NAME}' -m '${env.BUILD_TAG} ${commit}' + """ + // note: credentials used above don't work (need JENKINS-28335) + sh "git push origin gh-pages" + } + dir("$workDir/docker") { try { + git(url: "ssh://git@github.com/TRIQS/docker.git", branch: env.BRANCH_NAME, credentialsId: "ssh", changelog: false) + sh "echo '160000 commit ${commit}\t${projectName}' | git update-index --index-info" + sh """ + git commit --author='Flatiron Jenkins ' --allow-empty -m 'Autoupdate ${projectName}' -m '${env.BUILD_TAG}' + """ + // note: credentials used above don't work (need JENKINS-28335) + sh "git push origin ${env.BRANCH_NAME}" + } catch (err) { + echo "Failed to update docker repo" } } - } - } + } } + } } } catch (err) { if (env.BRANCH_NAME != "jenkins") emailext( subject: "\$PROJECT_NAME - Build # \$BUILD_NUMBER - FAILED", From 2c6149228a88e7f15f19415e66b5bc44f7da1e71 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Wed, 28 Mar 2018 16:28:52 +0200 Subject: [PATCH 36/44] _get_hermitian_quantity_from_gf to avoid code duplication --- python/sumk_dft.py | 109 +++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 63 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 7f527441..f60ab9e1 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -851,38 +851,22 @@ class SumkDFT(object): elif (ind1 < 0) and (ind2 < 0): self.deg_shells[ish].append([block1, block2]) - def analyse_block_structure_from_gf(self, G, threshold=1.e-5, include_shells=None, analyse_deg_shells = True): - r""" - Determines the block structure of local Green's functions by analysing - the structure of the corresponding non-interacting Green's function. - The resulting block structures for correlated shells are - stored in the :class:`SumkDFT.block_structure ` - attribute. + def _get_hermitian_quantity_from_gf(self, G): + """ Convert G to a Hermitian quantity - This is a safer alternative to analyse_block_structure, because - the full non-interacting Green's function is taken into account - and not just the density matrix and Hloc. + For G(tau) and G(iw), G(tau) is returned. + For G(t) and G(w), the spectral function is returned. Parameters ---------- - G : list of BlockGf of GfImFreq or GfImTime - the non-interacting Green's function for each inequivalent correlated shell - threshold : real, optional - If the difference between matrix elements is below threshold, - they are considered to be equal. - include_shells : list of integers, optional - List of correlated shells to be analysed. - If include_shells is not provided all correlated shells will be analysed. - analyse_deg_shells : bool - Whether to call the analyse_deg_shells function - after having finished the block structure analysis + G : list of BlockGf of GfImFreq, GfImTime, GfReFreq or GfReTime + the input Green's function Returns ------- - G : list of BlockGf of GfImFreq or GfImTime - the Green's function transformed into the new block structure + gf : list of BlockGf of GfImTime or GfReFreq + the output G(tau) or A(w) """ - # make a GfImTime from the supplied GfImFreq if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, @@ -922,6 +906,43 @@ class SumkDFT(object): g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi else: raise Exception("G must be a list of BlockGf of either GfImFreq, GfImTime, GfReFreq or GfReTime") + return gf + + + + def analyse_block_structure_from_gf(self, G, threshold=1.e-5, include_shells=None, analyse_deg_shells = True): + r""" + Determines the block structure of local Green's functions by analysing + the structure of the corresponding non-interacting Green's function. + The resulting block structures for correlated shells are + stored in the :class:`SumkDFT.block_structure ` + attribute. + + This is a safer alternative to analyse_block_structure, because + the full non-interacting Green's function is taken into account + and not just the density matrix and Hloc. + + Parameters + ---------- + G : list of BlockGf of GfImFreq, GfImTime, GfReFreq or GfReTime + the non-interacting Green's function for each inequivalent correlated shell + threshold : real, optional + If the difference between matrix elements is below threshold, + they are considered to be equal. + include_shells : list of integers, optional + List of correlated shells to be analysed. + If include_shells is not provided all correlated shells will be analysed. + analyse_deg_shells : bool + Whether to call the analyse_deg_shells function + after having finished the block structure analysis + + Returns + ------- + G : list of BlockGf of GfImFreq or GfImTime + the Green's function transformed into the new block structure + """ + + gf = self._get_hermitian_quantity_from_gf(G) # initialize the variables self.gf_struct_solver = [{} for ish in range(self.n_inequiv_shells)] @@ -1031,45 +1052,7 @@ class SumkDFT(object): null_space = compress(null_mask, vh, axis=0) return null_space.conjugate().transpose() - # make a GfImTime from the supplied GfImFreq - if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): - gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, - indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) - for g_sh in G] - for ish in range(len(gf)): - for name, g in gf[ish]: - g.set_from_inverse_fourier(G[ish][name]) - # keep a GfImTime from the supplied GfImTime - elif all(isinstance(g_sh._first(), GfImTime) for g_sh in G): - gf = G - # make a spectral function from the supplied GfReFreq - elif all(isinstance(g_sh._first(), GfReFreq) for g_sh in G): - gf = [g_sh.copy() for g_sh in G] - for ish in range(len(gf)): - for name, g in gf[ish]: - g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi - elif all(isinstance(g_sh._first(), GfReTime) for g_sh in G): - def get_delta_from_mesh(mesh): - w0 = None - for w in mesh: - if w0 is None: - w0 = w - else: - return w-w0 - gf = [BlockGf( - name_block_generator = [(name, - GfReFreq( - window=(-numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), - n_points=len(block.mesh), - indices=block.indices)) for name, block in g_sh]) - for g_sh in G] - - for ish in range(len(gf)): - for name, g in gf[ish]: - g.set_from_fourier(G[ish][name]) - g << 1.0j*(g-g.conjugate().transpose())/2.0/numpy.pi - else: - raise Exception("G must be a list of BlockGf of either GfImFreq, GfImTime, GfReFreq or GfReTime") + gf = self._get_hermitian_quantity_from_gf(G) if include_shells is None: # include all shells From 086573950bfd12e8f7cb2f095093466164008898 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Fri, 30 Mar 2018 15:46:40 +0200 Subject: [PATCH 37/44] bugfix: blocks get added twice Whenever both G and G^T support a symmetry, the block is added twice. This commit prevents that... --- python/sumk_dft.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index f60ab9e1..d01a8132 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1251,6 +1251,10 @@ class SumkDFT(object): d[block2] = T, False self.deg_shells[ish].append(d) + # a block was found, break out of the loop + break + + def density_matrix(self, method='using_gf', beta=40.0): """Calculate density matrices in one of two ways. From f8731f1bfefae265e1fc5bea2c05a7e01265e780 Mon Sep 17 00:00:00 2001 From: "Gernot J. Kraberger" Date: Tue, 3 Apr 2018 17:11:59 +0200 Subject: [PATCH 38/44] Fix test the testing threshold has to be more generous than the analyzing threshold --- python/sumk_dft.py | 4 ++++ test/analyze_block_structure_from_gf.py | 16 +++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index d01a8132..8f56f544 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -1029,6 +1029,10 @@ class SumkDFT(object): :class:`SumkDFT.block_structure ` attribute. + Due to the implementation and numerics, the maximum difference between + two matrix elements that are detected as equal can be a bit higher + (e.g. a factor of two) than the actual threshold. + Parameters ---------- G : list of BlockGf of GfImFreq or GfImTime diff --git a/test/analyze_block_structure_from_gf.py b/test/analyze_block_structure_from_gf.py index c777e9c3..23ada79f 100644 --- a/test/analyze_block_structure_from_gf.py +++ b/test/analyze_block_structure_from_gf.py @@ -166,7 +166,7 @@ for conjugate in conjugate_values: G_noisy['ud'][i:i+2,i:i+2] << G_noisy['ud'][i:i+2,i:i+2].transpose() # analyse the block structure - G_new = SK.analyse_block_structure_from_gf(G) + G_new = SK.analyse_block_structure_from_gf(G, 1.e-7) # transform G_noisy etc. to the new block structure G_noisy = SK.block_structure.convert_gf(G_noisy, block_structure1, beta = G_noisy.mesh.beta) @@ -200,18 +200,20 @@ for conjugate in conjugate_values: normalized_gfs.append(normalized_gf) for i in range(len(normalized_gfs)): for j in range(i+1,len(normalized_gfs)): - assert_gfs_are_close(normalized_gfs[i], normalized_gfs[j]) + # here, we use a threshold that is 1 order of magnitude less strict + # because of numerics + assert_gfs_are_close(normalized_gfs[i], normalized_gfs[j], 1.e-6) # now we check symm_deg_gf - # symmetrizing the GF as is has to leave it unchanged + # symmetrizing the GF has is has to leave it unchanged G_new_symm = G_new[0].copy() SK.symm_deg_gf(G_new_symm, 0) - assert_block_gfs_are_close(G_new[0], G_new_symm) + assert_block_gfs_are_close(G_new[0], G_new_symm, 1.e-6) # symmetrizing the noisy GF, which was carefully constructed, # has to give the same result as G_new[0] SK.symm_deg_gf(G_noisy, 0) - assert_block_gfs_are_close(G_new[0], G_noisy) + assert_block_gfs_are_close(G_new[0], G_noisy, 1.e-6) # check backward compatibility of symm_deg_gf # first, construct the old format of the deg shells @@ -222,9 +224,9 @@ for conjugate in conjugate_values: # symmetrizing the GF as is has to leave it unchanged G_new_symm << G_pre_transform SK.symm_deg_gf(G_new_symm, 0) - assert_block_gfs_are_close(G_new_symm, G_pre_transform) + assert_block_gfs_are_close(G_new_symm, G_pre_transform, 1.e-6) # symmetrizing the noisy GF pre transform, which was carefully constructed, # has to give the same result as G_pre_transform SK.symm_deg_gf(G_noisy_pre_transform, 0) - assert_block_gfs_are_close(G_noisy_pre_transform, G_pre_transform) + assert_block_gfs_are_close(G_noisy_pre_transform, G_pre_transform, 1.e-6) From 72c7f57110e6eacb470f50f5b45a7a45263dad89 Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Mon, 30 Apr 2018 19:00:08 +0200 Subject: [PATCH 39/44] Fix #89 Adjustments after recent triqs/cthyb gf_struct typechange -Adjust gf_struct keyword argument of CTHyb from dict : str -> indices to list of pairs: [ [str, indices], ... ] in accordance with recent cthyb/triqs changes -Fix set_operator_structure in srvo3_Gloc.py test accordingly -TODO: Adjust gf_struct appearences throughout dft_tools accordingly --- dft_dmft_cthyb.py | 2 +- doc/guide/SrVO3.rst | 2 +- doc/guide/images_scripts/dft_dmft_cthyb.py | 2 +- doc/guide/images_scripts/dft_dmft_cthyb_slater.py | 2 +- test/srvo3_Gloc.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dft_dmft_cthyb.py b/dft_dmft_cthyb.py index be87a74d..0ca76b16 100644 --- a/dft_dmft_cthyb.py +++ b/dft_dmft_cthyb.py @@ -57,7 +57,7 @@ gf_struct = SK.gf_struct_solver[0] Umat, Upmat = U_matrix_kanamori(n_orb=n_orb, U_int=U, J_hund=J) # Construct Hamiltonian and solver h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat, H_dump="H.txt") -S = Solver(beta=beta, gf_struct=gf_struct) +S = Solver(beta=beta, gf_struct=list(gf_struct)) if previous_present: chemical_potential = 0 diff --git a/doc/guide/SrVO3.rst b/doc/guide/SrVO3.rst index f9770b32..cbd77d4b 100644 --- a/doc/guide/SrVO3.rst +++ b/doc/guide/SrVO3.rst @@ -104,7 +104,7 @@ Kanamori definitions of :math:`U` and :math:`J`. Next, we construct the Hamiltonian and the solver:: h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat) - S = Solver(beta=beta, gf_struct=gf_struct) + S = Solver(beta=beta, gf_struct=list(gf_struct)) As you see, we take only density-density interactions into account. Other Hamiltonians with, e.g. with full rotational invariant interactions are: diff --git a/doc/guide/images_scripts/dft_dmft_cthyb.py b/doc/guide/images_scripts/dft_dmft_cthyb.py index c0ef8cd6..51c7ce93 100644 --- a/doc/guide/images_scripts/dft_dmft_cthyb.py +++ b/doc/guide/images_scripts/dft_dmft_cthyb.py @@ -65,7 +65,7 @@ Umat, Upmat = U_matrix_kanamori(n_orb=n_orb, U_int=U, J_hund=J) # Construct density-density Hamiltonian and solver h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat, H_dump="H.txt") -S = Solver(beta=beta, gf_struct=gf_struct) +S = Solver(beta=beta, gf_struct=list(gf_struct)) if previous_present: chemical_potential = 0 diff --git a/doc/guide/images_scripts/dft_dmft_cthyb_slater.py b/doc/guide/images_scripts/dft_dmft_cthyb_slater.py index a0c97304..62079b1b 100644 --- a/doc/guide/images_scripts/dft_dmft_cthyb_slater.py +++ b/doc/guide/images_scripts/dft_dmft_cthyb_slater.py @@ -66,7 +66,7 @@ Umat = U_matrix(n_orb=n_orb, U_int=U, J_hund=J, basis='cubic',) # Construct Hamiltonian and solver h_int = h_int_slater(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U_matrix=Umat) -S = Solver(beta=beta, gf_struct=gf_struct) +S = Solver(beta=beta, gf_struct=list(gf_struct)) if previous_present: chemical_potential = 0 diff --git a/test/srvo3_Gloc.py b/test/srvo3_Gloc.py index f10555e4..16988433 100644 --- a/test/srvo3_Gloc.py +++ b/test/srvo3_Gloc.py @@ -40,8 +40,8 @@ orb_names = ['%s'%i for i in range(num_orbitals)] orb_hybridized = False gf_struct = set_operator_structure(spin_names,orb_names,orb_hybridized) -glist = [ GfImFreq(indices=inner,beta=beta) for block,inner in gf_struct.iteritems()] -Sigma_iw = BlockGf(name_list = gf_struct.keys(), block_list = glist, make_copies = False) +glist = [ GfImFreq(indices=inner,beta=beta) for block,inner in gf_struct] +Sigma_iw = BlockGf(name_list = [block for block,inner in gf_struct], block_list = glist, make_copies = False) SK.set_Sigma([Sigma_iw]) Gloc = SK.extract_G_loc() From 9d87d0be1530f54926fb5024d2060a870a02063e Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Tue, 1 May 2018 11:55:31 +0200 Subject: [PATCH 40/44] Updating import directives, minor correction to commit --- dft_dmft_cthyb.py | 12 ++++++------ doc/documentation.rst | 2 +- doc/guide/SrVO3.rst | 14 +++++++------- doc/guide/analysis.rst | 10 +++++----- doc/guide/conversion.rst | 6 +++--- doc/guide/dftdmft_singleshot.rst | 2 +- doc/guide/images_scripts/Ce-gamma.py | 4 ++-- doc/guide/images_scripts/Ce-gamma_DOS.py | 4 ++-- doc/guide/images_scripts/dft_dmft_cthyb.py | 12 ++++++------ doc/guide/images_scripts/dft_dmft_cthyb_slater.py | 14 +++++++------- doc/guide/transport.rst | 4 ++-- doc/index.rst | 2 +- python/converters/plovasp/examples/ce/hf_solver.py | 2 +- .../converters/plovasp/examples/ce/test_ham_hf.py | 4 ++-- python/converters/wien2k_converter.py | 2 +- python/trans_basis.py | 4 ++-- shells/plovasp.bash.in | 2 +- shells/vasp_dmft.bash.in | 2 +- 18 files changed, 51 insertions(+), 51 deletions(-) diff --git a/dft_dmft_cthyb.py b/dft_dmft_cthyb.py index 0ca76b16..e5a26b32 100644 --- a/dft_dmft_cthyb.py +++ b/dft_dmft_cthyb.py @@ -1,10 +1,10 @@ import pytriqs.utility.mpi as mpi from pytriqs.operators.util import * from pytriqs.archive import HDFArchive -from pytriqs.applications.impurity_solvers.cthyb import * -from pytriqs.gf.local import * -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.converters.wien2k_converter import * +from triqs_cthyb import * +from pytriqs.gf import * +from triqs_dft_tools.sumk_dft import * +from triqs_dft_tools.converters.wien2k_converter import * dft_filename='Gd_fcc' U = 9.6 @@ -52,12 +52,12 @@ spin_names = ["up","down"] orb_names = [i for i in range(n_orb)] # Use GF structure determined by DFT blocks -gf_struct = SK.gf_struct_solver[0] +gf_struct = [(block, indices) for block, indices in SK.gf_struct_solver[0].iteritems()] # Construct U matrix for density-density calculations Umat, Upmat = U_matrix_kanamori(n_orb=n_orb, U_int=U, J_hund=J) # Construct Hamiltonian and solver h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat, H_dump="H.txt") -S = Solver(beta=beta, gf_struct=list(gf_struct)) +S = Solver(beta=beta, gf_struct=gf_struct) if previous_present: chemical_potential = 0 diff --git a/doc/documentation.rst b/doc/documentation.rst index 2ab27e0b..b000a6c8 100644 --- a/doc/documentation.rst +++ b/doc/documentation.rst @@ -1,4 +1,4 @@ -.. module:: pytriqs.applications.dft +.. module:: triqs_dft_tools .. _documentation: diff --git a/doc/guide/SrVO3.rst b/doc/guide/SrVO3.rst index cbd77d4b..85cb1ba6 100644 --- a/doc/guide/SrVO3.rst +++ b/doc/guide/SrVO3.rst @@ -23,11 +23,11 @@ Loading modules First, we load the necessary modules:: - from pytriqs.applications.dft.sumk_dft import * - from pytriqs.gf.local import * + from triqs_dft_tools.sumk_dft import * + from pytriqs.gf import * from pytriqs.archive import HDFArchive from pytriqs.operators.util import * - from pytriqs.applications.impurity_solvers.cthyb import * + from triqs_cthyb import * The last two lines load the modules for the construction of the :ref:`CTHYB solver `. @@ -80,7 +80,7 @@ each material individually. A guide on how to set the tail fit parameters is giv The next step is to initialize the -:class:`solver class `. +:class:`solver class `. It consist of two parts: #. Calculating the multi-band interaction matrix, and constructing the @@ -94,7 +94,7 @@ The first step is done using methods of the :ref:`TRIQS ` lib spin_names = ["up","down"] orb_names = [i for i in range(n_orb)] # Use GF structure determined by DFT blocks: - gf_struct = SK.gf_struct_solver[0] + gf_struct = [(block, indices) for block, indices in SK.gf_struct_solver[0].iteritems()] # Construct U matrix for density-density calculations: Umat, Upmat = U_matrix_kanamori(n_orb=n_orb, U_int=U, J_hund=J) @@ -104,7 +104,7 @@ Kanamori definitions of :math:`U` and :math:`J`. Next, we construct the Hamiltonian and the solver:: h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat) - S = Solver(beta=beta, gf_struct=list(gf_struct)) + S = Solver(beta=beta, gf_struct=gf_struct) As you see, we take only density-density interactions into account. Other Hamiltonians with, e.g. with full rotational invariant interactions are: @@ -213,7 +213,7 @@ and perform only one DMFT iteration. The resulting self energy can be tail fitte S.Sigma_iw[name].fit_tail(fit_n_moments = 4, fit_min_n = 60, fit_max_n = 140) Plot the self energy and adjust the tail fit parameters such that you obtain a -proper fit. The :meth:`fit_tail function ` is part +proper fit. The :meth:`fit_tail function ` is part of the :ref:`TRIQS ` library. For a self energy which is going to zero for :math:`i\omega \rightarrow 0` our suggestion is diff --git a/doc/guide/analysis.rst b/doc/guide/analysis.rst index 58203400..7563e287 100644 --- a/doc/guide/analysis.rst +++ b/doc/guide/analysis.rst @@ -27,7 +27,7 @@ Initialisation All tools described below are collected in an extension of the :class:`SumkDFT ` class and are loaded by importing the module :class:`SumkDFTTools `:: - from pytriqs.applications.dft.sumk_dft_tools import * + from triqs_dft_tools.sumk_dft_tools import * The initialisation of the class is equivalent to that of the :class:`SumkDFT ` class:: @@ -37,7 +37,7 @@ class:: Note that all routines available in :class:`SumkDFT ` are also available here. If required, we have to load and initialise the real frequency self energy. Most conveniently, -you have your self energy already stored as a real frequency :class:`BlockGf ` object +you have your self energy already stored as a real frequency :class:`BlockGf ` object in a hdf5 file:: ar = HDFArchive('case.h5', 'a') @@ -45,10 +45,10 @@ in a hdf5 file:: You may also have your self energy stored in text files. For this case the :ref:`TRIQS ` library offers the function :meth:`read_gf_from_txt`, which is able to load the data from text files of one Greens function block -into a real frequency :class:`ReFreqGf ` object. Loading each block separately and -building up a :class:´BlockGf ´ is done with:: +into a real frequency :class:`ReFreqGf ` object. Loading each block separately and +building up a :class:´BlockGf ´ is done with:: - from pytriqs.gf.local.tools import * + from pytriqs.gf.tools import * # get block names n_list = [n for n,nl in SK.gf_struct_solver[0].iteritems()] # load sigma for each block - in this example sigma is composed of 1x1 blocks diff --git a/doc/guide/conversion.rst b/doc/guide/conversion.rst index 16573cd0..e43b4796 100644 --- a/doc/guide/conversion.rst +++ b/doc/guide/conversion.rst @@ -107,7 +107,7 @@ Now we convert these files into an hdf5 file that can be used for the DMFT calculations. For this purpose we use the python module :class:`Wien2kConverter `. It is initialized as:: - from pytriqs.applications.dft.converters.wien2k_converter import * + from triqs_dft_tools.converters.wien2k_converter import * Converter = Wien2kConverter(filename = case) The only necessary parameter to this construction is the parameter `filename`. @@ -337,7 +337,7 @@ matrix of the imaginary part, and then move on to the next :math:`\mathbf{k}`-po The converter itself is used as:: - from pytriqs.applications.dft.converters.hk_converter import * + from triqs_dft_tools.converters.hk_converter import * Converter = HkConverter(filename = hkinputfile) Converter.convert_dft_input() @@ -371,7 +371,7 @@ as a placeholder for the actual prefix chosen by the user when creating the input for :program:`wannier90`. Once these two files are available, one can use the converter as follows:: - from pytriqs.applications.dft.converters import Wannier90Converter + from triqs_dft_tools.converters import Wannier90Converter Converter = Wannier90Converter(seedname='seedname') Converter.convert_dft_input() diff --git a/doc/guide/dftdmft_singleshot.rst b/doc/guide/dftdmft_singleshot.rst index 5afcc80e..f1ac3b81 100644 --- a/doc/guide/dftdmft_singleshot.rst +++ b/doc/guide/dftdmft_singleshot.rst @@ -22,7 +22,7 @@ The first thing is the :class:`SumkDFT ` class. It contains all basic routines that are necessary to perform a summation in k-space to get the local quantities used in DMFT. It is initialized by:: - from pytriqs.applications.dft.sumk_dft import * + from triqs_dft_tools.sumk_dft import * SK = SumkDFT(hdf_file = filename + '.h5') diff --git a/doc/guide/images_scripts/Ce-gamma.py b/doc/guide/images_scripts/Ce-gamma.py index a8d3453c..952065ea 100644 --- a/doc/guide/images_scripts/Ce-gamma.py +++ b/doc/guide/images_scripts/Ce-gamma.py @@ -1,5 +1,5 @@ -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.converters.wien2k_converter import * +from triqs_dft_tools.sumk_dft import * +from triqs_dft_tools.converters.wien2k_converter import * from pytriqs.applications.impurity_solvers.hubbard_I.hubbard_solver import Solver import os diff --git a/doc/guide/images_scripts/Ce-gamma_DOS.py b/doc/guide/images_scripts/Ce-gamma_DOS.py index bc72d14d..c96d756f 100644 --- a/doc/guide/images_scripts/Ce-gamma_DOS.py +++ b/doc/guide/images_scripts/Ce-gamma_DOS.py @@ -1,5 +1,5 @@ -from pytriqs.applications.dft.sumk_dft_tools import * -from pytriqs.applications.dft.converters.wien2k_converter import * +from triqs_dft_tools.sumk_dft_tools import * +from triqs_dft_tools.converters.wien2k_converter import * from pytriqs.applications.impurity_solvers.hubbard_I.hubbard_solver import Solver # Creates the data directory, cd into it: diff --git a/doc/guide/images_scripts/dft_dmft_cthyb.py b/doc/guide/images_scripts/dft_dmft_cthyb.py index 51c7ce93..74ad4a42 100644 --- a/doc/guide/images_scripts/dft_dmft_cthyb.py +++ b/doc/guide/images_scripts/dft_dmft_cthyb.py @@ -1,9 +1,9 @@ import pytriqs.utility.mpi as mpi from pytriqs.operators.util import * from pytriqs.archive import HDFArchive -from pytriqs.applications.impurity_solvers.cthyb import * -from pytriqs.gf.local import * -from pytriqs.applications.dft.sumk_dft import * +from triqs_cthyb import * +from pytriqs.gf import * +from triqs_dft_tools.sumk_dft import * dft_filename='SrVO3' U = 4.0 @@ -30,7 +30,7 @@ p["fit_min_n"] = 30 p["fit_max_n"] = 60 # If conversion step was not done, we could do it here. Uncomment the lines it you want to do this. -#from pytriqs.applications.dft.converters.wien2k_converter import * +#from triqs_dft_tools.converters.wien2k_converter import * #Converter = Wien2kConverter(filename=dft_filename, repacking=True) #Converter.convert_dft_input() #mpi.barrier() @@ -58,14 +58,14 @@ spin_names = ["up","down"] orb_names = [i for i in range(n_orb)] # Use GF structure determined by DFT blocks -gf_struct = SK.gf_struct_solver[0] +gf_struct = [(block, indices) for block, indices in SK.gf_struct_solver[0].iteritems()] # Construct U matrix for density-density calculations Umat, Upmat = U_matrix_kanamori(n_orb=n_orb, U_int=U, J_hund=J) # Construct density-density Hamiltonian and solver h_int = h_int_density(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U=Umat, Uprime=Upmat, H_dump="H.txt") -S = Solver(beta=beta, gf_struct=list(gf_struct)) +S = Solver(beta=beta, gf_struct=gf_struct) if previous_present: chemical_potential = 0 diff --git a/doc/guide/images_scripts/dft_dmft_cthyb_slater.py b/doc/guide/images_scripts/dft_dmft_cthyb_slater.py index 62079b1b..f66e0526 100644 --- a/doc/guide/images_scripts/dft_dmft_cthyb_slater.py +++ b/doc/guide/images_scripts/dft_dmft_cthyb_slater.py @@ -1,10 +1,10 @@ import pytriqs.utility.mpi as mpi from pytriqs.operators.util import * from pytriqs.archive import HDFArchive -from pytriqs.applications.impurity_solvers.cthyb import * -from pytriqs.gf.local import * -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.converters.wien2k_converter import * +from triqs_cthyb import * +from pytriqs.gf import * +from triqs_dft_tools.sumk_dft import * +from triqs_dft_tools.converters.wien2k_converter import * dft_filename='SrVO3' U = 9.6 @@ -31,7 +31,7 @@ p["fit_min_n"] = 30 p["fit_max_n"] = 60 # If conversion step was not done, we could do it here. Uncomment the lines it you want to do this. -#from pytriqs.applications.dft.converters.wien2k_converter import * +#from triqs_dft_tools.converters.wien2k_converter import * #Converter = Wien2kConverter(filename=dft_filename, repacking=True) #Converter.convert_dft_input() #mpi.barrier() @@ -59,14 +59,14 @@ spin_names = ["up","down"] orb_names = [i for i in range(n_orb)] # Use GF structure determined by DFT blocks -gf_struct = SK.gf_struct_solver[0] +gf_struct = [(block, indices) for block, indices in SK.gf_struct_solver[0].iteritems()] # Construct Slater U matrix Umat = U_matrix(n_orb=n_orb, U_int=U, J_hund=J, basis='cubic',) # Construct Hamiltonian and solver h_int = h_int_slater(spin_names, orb_names, map_operator_structure=SK.sumk_to_solver[0], U_matrix=Umat) -S = Solver(beta=beta, gf_struct=list(gf_struct)) +S = Solver(beta=beta, gf_struct=gf_struct) if previous_present: chemical_potential = 0 diff --git a/doc/guide/transport.rst b/doc/guide/transport.rst index 46b80306..38cd48f6 100644 --- a/doc/guide/transport.rst +++ b/doc/guide/transport.rst @@ -76,8 +76,8 @@ Using the transport code First we have to read the Wien2k files and store the relevant information in the hdf5 archive:: - from pytriqs.applications.dft.converters.wien2k_converter import * - from pytriqs.applications.dft.sumk_dft_tools import * + from triqs_dft_tools.converters.wien2k_converter import * + from triqs_dft_tools.sumk_dft_tools import * Converter = Wien2kConverter(filename='case', repacking=True) Converter.convert_transport_input() diff --git a/doc/index.rst b/doc/index.rst index 3867ab87..32d930ab 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -1,6 +1,6 @@ .. index:: DFTTools -.. module:: pytriqs.applications.dft +.. module:: triqs_dft_tools .. _dft: diff --git a/python/converters/plovasp/examples/ce/hf_solver.py b/python/converters/plovasp/examples/ce/hf_solver.py index 64005660..07d67aaf 100644 --- a/python/converters/plovasp/examples/ce/hf_solver.py +++ b/python/converters/plovasp/examples/ce/hf_solver.py @@ -21,7 +21,7 @@ ################################################################################ from types import * -#from pytriqs.applications.dft.U_matrix import * +#from triqs_dft_tools.U_matrix import * from U_matrix import * from pytriqs.gf import * #from hubbard_I import gf_hi_fullu, sigma_atomic_fullu diff --git a/python/converters/plovasp/examples/ce/test_ham_hf.py b/python/converters/plovasp/examples/ce/test_ham_hf.py index 903b0c20..1243b85c 100644 --- a/python/converters/plovasp/examples/ce/test_ham_hf.py +++ b/python/converters/plovasp/examples/ce/test_ham_hf.py @@ -1,6 +1,6 @@ -#from pytriqs.applications.dft.sumk_dft import * +#from triqs_dft_tools.sumk_dft import * from sumk_dft import * -#from pytriqs.applications.dft.converters.wien2k_converter import * +#from triqs_dft_tools.converters.wien2k_converter import * from converters.vasp_converter import * #from pytriqs.applications.impurity_solvers.hubbard_I.hubbard_solver import Solver from hf_solver import Solver diff --git a/python/converters/wien2k_converter.py b/python/converters/wien2k_converter.py index e5f1e544..8664e0b0 100644 --- a/python/converters/wien2k_converter.py +++ b/python/converters/wien2k_converter.py @@ -502,7 +502,7 @@ class Wien2kConverter(ConverterTools): - symmetries from :file:`case.outputs`, if those Wien2k files are present and stores the data in the hdf5 archive. - This function is automatically called by :meth:`convert_dft_input `. + This function is automatically called by :meth:`convert_dft_input `. """ diff --git a/python/trans_basis.py b/python/trans_basis.py index 135e72c9..91a014a5 100644 --- a/python/trans_basis.py +++ b/python/trans_basis.py @@ -1,5 +1,5 @@ -from pytriqs.applications.dft.sumk_dft import * -from pytriqs.applications.dft.converters import Wien2kConverter +from triqs_dft_tools.sumk_dft import * +from triqs_dft_tools.converters import Wien2kConverter from pytriqs.gf import * from pytriqs.archive import * import pytriqs.utility.mpi as mpi diff --git a/shells/plovasp.bash.in b/shells/plovasp.bash.in index ce55bcde..9229f4e1 100755 --- a/shells/plovasp.bash.in +++ b/shells/plovasp.bash.in @@ -1,4 +1,4 @@ #!/bin/bash -@CMAKE_INSTALL_PREFIX@/bin/pytriqs -m pytriqs.applications.dft.converters.plovasp.converter $@ +@CMAKE_INSTALL_PREFIX@/bin/pytriqs -m triqs_dft_tools.converters.plovasp.converter $@ diff --git a/shells/vasp_dmft.bash.in b/shells/vasp_dmft.bash.in index ca6aecd0..ad4f6543 100755 --- a/shells/vasp_dmft.bash.in +++ b/shells/vasp_dmft.bash.in @@ -83,5 +83,5 @@ stdbuf -o 0 $MPIRUN_CMD -np $NPROC "$VASP_DIR" & PYTRIQS=@CMAKE_INSTALL_PREFIX@/bin/pytriqs -$MPIRUN_CMD -np $NPROC $PYTRIQS -m pytriqs.applications.dft.converters.plovasp.sc_dmft $(jobs -p) $NITER $DMFT_SCRIPT 'plo.cfg' || kill %1 +$MPIRUN_CMD -np $NPROC $PYTRIQS -m triqs_dft_tools.converters.plovasp.sc_dmft $(jobs -p) $NITER $DMFT_SCRIPT 'plo.cfg' || kill %1 From 5675e5a227c29a95605b64011296d1e5858a724b Mon Sep 17 00:00:00 2001 From: Nils Wentzell Date: Tue, 1 May 2018 12:02:11 +0200 Subject: [PATCH 41/44] Add travis and clang-format file --- .clang-format | 45 +++++++++++++++++++++++++++++++++++++++++++++ .travis.yml | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 .clang-format create mode 100644 .travis.yml diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..10b38401 --- /dev/null +++ b/.clang-format @@ -0,0 +1,45 @@ +BasedOnStyle: LLVM + +AccessModifierOffset: 0 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlinesLeft: false +AlignOperands: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakStringLiterals: false +ColumnLimit: 150 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 3 +ContinuationIndentWidth: 3 +Cpp11BracedListStyle: true +DerivePointerBinding : false +IndentCaseLabels: true +IndentWidth: 2 +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation : All +PointerAlignment: Right +ReflowComments: false +SortIncludes: false +SpaceAfterControlStatementKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceInEmptyParentheses: false +SpacesInParentheses: false +Standard: Cpp11 +TabWidth: 2 +UseTab: Never diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..584616bd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,48 @@ + +language: cpp +sudo: required +dist: trusty + +compiler: + - gcc + # - clang + +before_install: + - sudo add-apt-repository 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main' -y + - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + - sudo apt-get update + - sudo apt-get install -y --allow-unauthenticated g++-7 clang-5.0 + - export LIBRARY_PATH=/usr/lib/llvm-5.0/lib:$LIBRARY_PATH + - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7 + - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-5.0 60 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-5.0 + - sudo apt-get install -y --allow-unauthenticated libboost-all-dev cmake git libgfortran3 gfortran openmpi-bin openmpi-common openmpi-doc libopenmpi-dev libblas-dev liblapack-dev libfftw3-dev libgmp-dev hdf5-tools libhdf5-serial-dev python-h5py python-dev python-numpy python-scipy python-jinja2 python-virtualenv python-matplotlib python-tornado python-zmq python-mpi4py python-mako clang-format-5.0 libclang-5.0-dev python-clang-5.0 python-sphinx libjs-mathjax valgrind libnfft3-dev + +install: true + +script: + # ===== Set up Cpp2Py + - git clone https://github.com/triqs/cpp2py + - mkdir cpp2py/build && cd cpp2py/build + - git checkout master + - cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/${CXX} -DPYTHON_INTERPRETER=/usr/bin/python -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/root_install + - make -j8 install + - cd $TRAVIS_BUILD_DIR + - source root_install/share/cpp2pyvars.sh + # ===== Set up TRIQS + - git clone https://github.com/TRIQS/triqs --branch unstable + - mkdir triqs/build && cd triqs/build + - git checkout unstable + - cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/${CXX} -DBuild_Tests=OFF -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/root_install -DCMAKE_BUILD_TYPE=Debug + - make -j8 install + - cd $TRAVIS_BUILD_DIR + - source root_install/share/triqsvars.sh + # ===== Set up dft_tools and Test using fsanitize=address + - mkdir build && cd build + - cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=/usr/bin/${CXX} -DCMAKE_CXX_FLAGS='-fsanitize=address -fno-omit-frame-pointer -fuse-ld=gold' + - make -j8 + - export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer + - export ASAN_OPTIONS=symbolize=1:detect_leaks=0 + - export CTEST_OUTPUT_ON_FAILURE=1 + - if [ "$CXX" = g++ ]; then export LD_PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/7/libasan.so; elif [ "$CXX" = clang++ ]; then export LD_PRELOAD=/usr/lib/llvm-5.0/lib/clang/5.0.1/lib/linux/libclang_rt.asan-x86_64.so; fi + - cd test && ctest From d0ea51a1f532c040a0879cb9e59676fef582baa1 Mon Sep 17 00:00:00 2001 From: Manuel Date: Wed, 2 May 2018 16:07:51 -0400 Subject: [PATCH 42/44] Add make_copies in BlockGf construction. --- python/sumk_dft.py | 14 ++++++-------- test/analyze_block_structure_from_gf2.py | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/python/sumk_dft.py b/python/sumk_dft.py index 8f56f544..1c5c1f99 100644 --- a/python/sumk_dft.py +++ b/python/sumk_dft.py @@ -870,8 +870,8 @@ class SumkDFT(object): # make a GfImTime from the supplied GfImFreq if all(isinstance(g_sh._first(), GfImFreq) for g_sh in G): gf = [BlockGf(name_block_generator = [(name, GfImTime(beta=block.mesh.beta, - indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh]) - for g_sh in G] + indices=block.indices,n_points=len(block.mesh)+1)) for name, block in g_sh], + make_copies=False) for g_sh in G] for ish in range(len(gf)): for name, g in gf[ish]: g.set_from_inverse_fourier(G[ish][name]) @@ -892,12 +892,10 @@ class SumkDFT(object): w0 = w else: return w-w0 - gf = [BlockGf( - name_block_generator = [(name, - GfReFreq( - window=(-numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), - n_points=len(block.mesh), - indices=block.indices)) for name, block in g_sh]) + gf = [BlockGf(name_block_generator = [(name, GfReFreq( + window=(-numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), + numpy.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), + n_points=len(block.mesh), indices=block.indices)) for name, block in g_sh], make_copies=False) for g_sh in G] for ish in range(len(gf)): diff --git a/test/analyze_block_structure_from_gf2.py b/test/analyze_block_structure_from_gf2.py index d371a9c5..c3cf73e3 100644 --- a/test/analyze_block_structure_from_gf2.py +++ b/test/analyze_block_structure_from_gf2.py @@ -41,7 +41,7 @@ delta[0,1] << (V[0,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[0,1]*V[1,1].conjuga delta[1,0] << (V[1,0]*V[0,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[0,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 delta[1,1] << (V[1,0]*V[1,0].conjugate()*inverse(Omega-b1)+V[1,1]*V[1,1].conjugate()*inverse(Omega-b2+0.02j))/2.0 # construct G -G = BlockGf(name_block_generator=(('ud',GfReFreq(window=(-5,5), indices=range(10), n_points=1001)),)) +G = BlockGf(name_block_generator=[('ud',GfReFreq(window=(-5,5), indices=range(10), n_points=1001))], make_copies=False) for i in range(0,10,2): G['ud'][i:i+2,i:i+2] << inverse(Omega-delta+0.02j) G['ud'] << inverse(inverse(G['ud']) - Hloc) @@ -86,7 +86,7 @@ def get_delta_from_mesh(mesh): Gt = BlockGf(name_block_generator = [(name, GfReTime(window=(-np.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh)), np.pi*(len(block.mesh)-1) / (len(block.mesh)*get_delta_from_mesh(block.mesh))), n_points=len(block.mesh), - indices=block.indices)) for name, block in G]) + indices=block.indices)) for name, block in G], make_copies=False) Gt['ud'].set_from_inverse_fourier(G['ud']) From 4ae6571a174fd22594a691c96b59a584b6fb7410 Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Mon, 21 May 2018 10:44:01 -0400 Subject: [PATCH 43/44] [cmake] Add deb packaging rules --- CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0e35fa4..7d6c20ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,3 +65,19 @@ if(${Build_Documentation}) endif() add_subdirectory(doc) endif() + +#-------------------------------------------------------- +# Packaging +#-------------------------------------------------------- +option(BUILD_DEBIAN_PACKAGE "Build a deb package" OFF) +if(BUILD_DEBIAN_PACKAGE) + if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr") + message(FATAL_ERROR "CMAKE_INSTALL_PREFIX must be /usr for packaging") + endif() + SET(CPACK_GENERATOR "DEB") + SET(CPACK_PACKAGE_VERSION ${DFT_TOOLS_VERSION}) + SET(CPACK_PACKAGE_CONTACT "https://github.com/TRIQS/dft_tools") + EXECUTE_PROCESS(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CMAKE_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.23), libgcc1 (>= 1:8), libstdc++6, python, libpython2.7, libopenmpi1.10, libhdf5-10, libgmp10, libfftw3-double3, libibverbs1, libgfortran3, zlib1g, libsz2, libhwloc5, libquadmath0, libaec0, libnuma1, libltdl7, libblas3, liblapack3, python-numpy, python-h5py, python-jinja2, python-mako, python-mpi4py, python-matplotlib, python-scipy, cpp2py (= ${DFT_TOOLS_VERSION}), triqs (= ${DFT_TOOLS_VERSION})") + INCLUDE(CPack) +endif() From 57840986bc66484d0be1c852a6d837a2a4c12d1f Mon Sep 17 00:00:00 2001 From: Dylan Simon Date: Mon, 21 May 2018 16:04:00 -0400 Subject: [PATCH 44/44] [cmake] deb pkg works with libgcc1 1:6 The default on xenial --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d6c20ea..30c49481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,6 @@ if(BUILD_DEBIAN_PACKAGE) SET(CPACK_PACKAGE_VERSION ${DFT_TOOLS_VERSION}) SET(CPACK_PACKAGE_CONTACT "https://github.com/TRIQS/dft_tools") EXECUTE_PROCESS(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CMAKE_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.23), libgcc1 (>= 1:8), libstdc++6, python, libpython2.7, libopenmpi1.10, libhdf5-10, libgmp10, libfftw3-double3, libibverbs1, libgfortran3, zlib1g, libsz2, libhwloc5, libquadmath0, libaec0, libnuma1, libltdl7, libblas3, liblapack3, python-numpy, python-h5py, python-jinja2, python-mako, python-mpi4py, python-matplotlib, python-scipy, cpp2py (= ${DFT_TOOLS_VERSION}), triqs (= ${DFT_TOOLS_VERSION})") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.23), libgcc1 (>= 1:6), libstdc++6, python, libpython2.7, libopenmpi1.10, libhdf5-10, libgmp10, libfftw3-double3, libibverbs1, libgfortran3, zlib1g, libsz2, libhwloc5, libquadmath0, libaec0, libnuma1, libltdl7, libblas3, liblapack3, python-numpy, python-h5py, python-jinja2, python-mako, python-mpi4py, python-matplotlib, python-scipy, cpp2py (= ${DFT_TOOLS_VERSION}), triqs (= ${DFT_TOOLS_VERSION})") INCLUDE(CPack) endif()