def ranges(device_configuration,method): """ Returns the max basis set and projector radii, in Angstrom @param device_configuration The device configuration to check. """ # Import required modules. from NL.Calculators.BulkCalculatorInterface import minimalBasis calculator = device_configuration.calculator() # If no calculator is attached, use specified method with default parameters if calculator is None: # In order not to destroy the input, we should make a local copy in that case print "No calculator on configuration, using %s with default parameters" % method if method=='DFT': calculator = DeviceLCAOCalculator() else: calculator = DeviceHuckelCalculator() # If it is a device configuration we will need to take into account projectors. if isinstance(calculator, DeviceLCAOCalculator): # Get the exchange-correlation calculator. xc_calculator = calculator.exchangeCorrelation()._radialBackEngine() # Get the minimal basis. minimal_basis = minimalBasis(device_configuration, calculator.basisSet()) # Find the basis range. basis_range = 0.0 for basis in minimal_basis: b = basis._backEngine(xc_calculator) N = b.size() for i in range(N): basis_range = max(basis_range, b[i].range()) # Find the projector range. projector_range = 0.0 for basis in minimal_basis: pseudopotential = basis.pseudopotential() pseudopotential.load() projectors = pseudopotential._projectors() N = projectors.size() for i in range(N): projector_range = max(projector_range, projectors[i].range()) return ((basis_range*Bohr).convertTo(Angstrom),(projector_range*Bohr).convertTo(Angstrom)) elif isinstance(calculator, DeviceHuckelCalculator): # Get the builder. builder = calculator._builder()(device_configuration, calculator) matrix_calculator = builder.createMatrixCalculator() # Find the basis ranges. basis_range = 0.0 for e in numpy.unique(device_configuration.elements()): ranges = matrix_calculator.basisSet().ranges(e.symbol()) for i in range(ranges.size()): basis_range = max(basis_range, ranges[i]) return ((basis_range*Bohr).convertTo(Angstrom),0.) def minimal_nextnext_distance(electrode): ''' Computes the smallest distance between the atoms in the electrode and the atoms in the corresponding next-next neighbor electrode cell @param electrode A BulkConfiguration @return Minimal distance, in Angstrom ''' # Length of electrode C vector in Z electrode_Cz = electrode.bravaisLattice().primitiveVectors()[2,2].inUnitsOf(Angstrom) # Original electrode coordinates elec_coords = electrode.cartesianCoordinates().inUnitsOf(Angstrom) # Coordinates of atoms in next-next cell test_coords = elec_coords+numpy.array([0,0,2.*electrode_Cz]) # Compute the distance from each atom in next-next cell to all atoms in original cell (order N) distances = [] for test in test_coords: distances.append(numpy.sqrt(((test-elec_coords)**2).sum(axis=1))) # Return the smallest such distance return numpy.min(numpy.array(distances)) def print_status(lr,dist,basis_range,projector_range): if dist < 2.*basis_range: print 'WARNING: Truncation of direct basis pair overlaps will occur in the %s electrode in this system. Your results will be incorrect!' % lr elif dist < 2.0*(basis_range + projector_range): print 'NOTE: Truncation of some second-order interactions will occur in the %s electrode in this system. This may influence convergence and the results.' % lr else: print 'The %s electrode is sufficiently long to include all interations.' % lr def validateElectrodes(device_configuration, method): """ Method for checking that the electrodes is long enough @param device_configuration The device configuration to check """ if device_configuration==None: return None # Compute the maximum basis set and projector (for DFT only) radius basis_range,projector_range = ranges(device_configuration,method) left_mini_dist = minimal_nextnext_distance(device_configuration.electrodes()[0]) right_mini_dist = minimal_nextnext_distance(device_configuration.electrodes()[1]) print 'Maximum basis set radius = %8.4f Ang' % basis_range print 'Maximum basis + projector radius = %8.4f Ang' % (basis_range + projector_range) print 'Basis set overlap range = %8.4f Ang' % (2.0*basis_range) print 'Maximum interaction range = %8.4f Ang' % (2.0*(basis_range + projector_range)) print 'Left electrode, truncation distance = %8.4f Ang' % left_mini_dist print 'Right electrode, truncation distance = %8.4f Ang' % right_mini_dist print '(Truncation occurs at the smallest atom-atom distance between electrode and its next-nearest neighbor cell)\n' print_status("LEFT",left_mini_dist,basis_range,projector_range) print print_status("RIGHT",right_mini_dist,basis_range,projector_range) return device_configuration # Initialize the Analyzer builder = Builder() builder.title('Electrode length check') # Set the Analysis function builder.setConfigurationGenerator(validateElectrodes) # Set up a Analysis widget interface builder.configuration('device_configuration', label='Device configuration', text='Drop system here') builder.choice('method', [ ('DFT', 'DFT'), ('Extended Huckel', 'Extended Huckel'), ], 'DFT', 'Default method')