Skip to content

Commit

Permalink
Fixes and Examples
Browse files Browse the repository at this point in the history
  • Loading branch information
louisponet committed Mar 9, 2018
1 parent b3da30f commit 55bed15
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 20 deletions.
84 changes: 84 additions & 0 deletions examples/1createandrun_job_from_cif.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#This example requires cif2cell to be installed, and have it set in your PATH.
using DFControl

#This example goes through how one would create a job from scratch, using a .cif file for the Structure.

#First go to your favourite Crystal structure database and download the .cif you want to use.
#e.g. Si (F d -3 m :1) : http://www.crystallography.net/cod/9011998.cif

#We want to run an 'scf' and 'bands' calculation using QuantumEspresso.


#Variables that will be passed to the `DFJob` constructor.

name = "Si" #this name will also be given to the Structure inside the DFJob
local_dir = "/home/ponet/Documents/Si"
server_dir = "/home/ponet/Si"
run_command = "mpirun -np 24"
bin_dir = "/usr/local/bin" #this is defaulted to the users bin dir = "~/bin/", it is the directory where pw.x etc will be called from

pseudo_set = :pbesol #nonrelativistic calculation ( assumes you set up the pseudos, as demonstrated in the README)
pseudo_specifier = "paw" #this selects the correct pseudo if multiple belong to the pseudo_set. If you don't specify this, the first one in the set will be used.

#The header holds all the other information inside a job scriptfile that is not recognized as input and output.
header = ["#SBATCH -N 1", "#SBATCH --ntasks-per-node=24",
"#SBATCH --time=24:00:00", "#SBATCH -p defpart",
"module load open-mpi/gcc/1.10.4-hfi", "module load mkl/2016.1.056"
]

#The various calculations we want to run and the flags and data to pass to them are defined in two ways:
# - calculation specific flags and data are associated with the calculation they belong to
# - common flags can be defined as Pair{Symbol, Any} varargs at the end of the constructor call.
scf_data = Dict(:k_points => (6, 6, 6, 1, 1, 1), :flags => [:verbosity => "'low'"])
bands_data = Dict(:k_points => [(0.5, 0.5, 0.5, 100.),
(0.0, 0.0, 0.0, 100.),
(0.0, 0.5, 0.0, 1.)],
:flags => [:verbosity => "'high'", :nbnd => 8])

calculations = [:scf => scf_data, :bands => bands_data] #the order here is the order in which the calculations will run!

#Now we load the cif file and create a `DFJob` from it.

job = DFJob(name, local_dir, "/home/ponet/Downloads/9011998.cif", calculations,
:prefix => "'silicon'",
:restart_mode => "'from_scratch'",
:ecutwfc => 18.0,
:mixing_mode => "'plain'",
:mixing_beta => 0.7,
:conv_thr => 1.0e-8,
#kwargs
server_dir = server_dir,
bin_dir = bin_dir,
run_command = run_command,
header = header,
pseudo_set = :pbesol,
pseudo_specifier = pseudo_specifier
)
# An additional kwarg is `server=get_default_server()`, which is set to the server you have defined while following the setup in README.
# This can ofcourse be changed to a different server.

#Now the job can be submitted to the server to run.
submit_job(job)
#this first saves the job and it's input files to the `job.local_dir` then pushes the `job.tt` file and the inputs to the `job.server_dir` on `job.server`, and runs the `qsub job.tt` command.
#You can check the job.local_dir to see the input files and `job.tt` script.

#you can observe the slurm qstat by doing
qstat()
#or watch it by
watch_qstat()
#these default to run the commands on the default server

#hopefully everything went according to plan and we can watch our outputs
outputs = pull_outputs(job)

#now the bandstructure can be plotted
bands = read_qe_output(outputs[2])[:bands]
#alt:
bands = read_qe_bands_file(outputs[2])

fermi = read_qe_output(outputs[1])[:fermi]
#alt:
fermi = read_fermi_from_qe_output(outputs[1])
using Plots

plot(bands, fermi=fermi)
30 changes: 30 additions & 0 deletions examples/2edit_job_resubmit.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#This example assumes that you ran through the first one.
# It will show how to load a job from a server, and change flags.

using DFControl

server_dir = "Si/"
local_dir = "/home/ponet/Documents/Si"
job = load_server_job(server_dir, local_dir)
#shorthand:
job = ldsj(server_dir, local_dir) #for other shorthands see DFControl/src/shorthands.jl

#change flags
change_flags!(job, :ecutwfc => 25.0) #more `Pair{Symbol, Any}`'s can be given as varargs.
#shorthand: chfls!
#change_flags! will only go through already set flags to change them,
#if you want to set new flags simply do (it can also be used to change already set flags):

set_flags!(job, :ecut_rho => 80.) #won't work, it goes through the QE documentation to find the allowed flags for the input files in the job, and also tries to convert the given value to what it should be.

set_flags!(job, :ecutrho => 80., :diagonalization => "'david'")
#shorthand: stfls!

#now we might not want to run all the calculations again.
#one can change the job "flow":
change_flow!(job, "scf" => false) #again, more `Pair{String, Bool}`'s can be given as varargs
#This looks through all the calculations inside the job, if the `calculation.name` (derived from it's filename) contains a given `String`, it will set `calculation.run` to the corresponding `Bool`.
#If a job has calculations/inputs that don't need to run, their line will be commented out in `job.tt` script.

#now we can resubmit the job with the changed flags
sbmj(job)
3 changes: 2 additions & 1 deletion src/DFControl.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__precompile__(true)
__precompile__()
module DFControl
# using Reexport
using RecipesBase
Expand Down Expand Up @@ -105,6 +105,7 @@ module DFControl
export set_default_server
export configure_default_pseudos
export remove_default_pseudo_dir
export get_default_pseudo
export set_default_job_header
export @add_default
export load_defaults
Expand Down
2 changes: 1 addition & 1 deletion src/defaults.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function get_default_pseudo_dir(pseudo_set)
end

"""
configure_default_pseudos!(server = get_default_server(), pseudo_dirs=get_default_pseudo_dirs())
configure_default_pseudos(server = get_default_server(), pseudo_dirs=get_default_pseudo_dirs())
Reads the specified `default_pseudo_dirs` on the `default_server` and sets up the `default_pseudos` variable, and also adds all the entries to the `user_defaults.jl` file.
"""
Expand Down
28 changes: 16 additions & 12 deletions src/job.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,38 @@ mutable struct DFJob
end

#TODO implement abinit
# function DFJob(job_name, local_dir, calculations::Array{Pair{Union{Symbol, String}, Dict},1}, atoms, cell_parameters=eye(3);
function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStructure;
function DFJob(job_name, local_dir, structure::AbstractStructure, calculations::Vector, common_flags...;
server=get_default_server(),
server_dir="",
package=:qe,
bin_dir="~/bin/",
run_command="mpirun -np 24",
common_flags=Dict{Symbol,Any}(),
pseudo_set=:default,
pseudo_specifier="",
header=get_default_job_header())

@assert package==:qe "Only implemented for Quantum Espresso!"
local_dir = form_directory(local_dir)
job_atoms = convert_2atoms(atoms,pseudo_set=pseudo_set, pseudo_specifier=pseudo_specifier)
job_calcs = DFInput[]
if typeof(common_flags) != Dict
common_flags = Dict(common_flags)
end

bin_dir = form_directory(bin_dir)
req_flags = Dict(:prefix => "'$job_name'",
:outdir => "'$server_dir'",
:ecutwfc => 25.)
merge!(req_flags, common_flags)
for (calc, data) in calculations
calc_ = typeof(calc) == String ? Symbol(calc) : calc
if in(calc_, [Symbol("vc-relax"), :relax, :scf])
k_points = pop!(data, :k_points, [1, 1, 1, 0, 0, 0])
k_points = get(data, :k_points, [1, 1, 1, 0, 0, 0])
k_option = :automatic
elseif calc_ == :nscf
k_points = pop!(data, :k_points, (1, 1, 1))
k_points = get(data, :k_points, (1, 1, 1))
k_grid = gen_k_grid(k_points..., :nscf)
k_option = :crystal
elseif calc_ == :bands
k_points = pop!(data, :k_points, [0., 0., 0., 1.])
k_points = get(data, :k_points, [[0., 0., 0., 1.]])
num_k = 0.0
for point in k_points
num_k += point[4]
Expand All @@ -77,7 +74,7 @@ function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStr
end
k_option = :crystal_b
end
flags = pop!(data, :flags, Dict{Symbol, Any}())
flags = get(data, :flags, Dict{Symbol, Any}())
push!(flags, :calculation => "'$(string(calc_))'")
input_ = QEInput(string(calc_) * ".in",
QEControlBlock[],
Expand All @@ -87,15 +84,16 @@ function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStr
true)
set_flags!(input_, req_flags..., print=false)
set_flags!(input_, flags..., print=false)
change_atoms!(input_, job_atoms, pseudo_set = pseudo_set, pseudo_specifier = pseudo_specifier, print=false)
push!(job_calcs, input_)
end
out = DFJob(job_name, structure, job_calcs, local_dir, server, server_dir, header)
change_atoms!(out, structure.atoms, pseudo_set = pseudo_set, pseudo_specifier= pseudo_specifier)
return DFJob(job_name, structure, job_calcs, local_dir, server, server_dir, header)
end

function DFJob(job_name, local_dir, calculations::Vector, ciffile::String; kwargs...)
function DFJob(job_name, local_dir, ciffile::String, calculations::Vector, args...; kwargs...)
structure = Structure(ciffile, name=job_name)
return DFJob(job_name, local_dir, calculations, structure; kwargs...)
return DFJob(job_name, local_dir, structure, calculations, args... ; kwargs...)
end

function DFJob(job::DFJob, flagstoset...;
Expand Down Expand Up @@ -279,6 +277,12 @@ function push_job(job::DFJob, newfiles)
if !ispath(job.local_dir)
error("Please save the job locally first using save_job(job)!")
else
try
run(`ssh -t $(job.server) touch $(job.server_dir * "tmp.in")`)
run(`ssh -t $(job.server) rm $(job.server_dir * "tmp.in")`)
catch
run(`ssh -t $(job.server) mkdir $(job.server_dir)`)
end
for file in newfiles
run(`scp $(job.local_dir * file) $(job.server * ":" * job.server_dir)`)
end
Expand Down
39 changes: 33 additions & 6 deletions src/qe/fileio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ function read_qe_output(filename::String, T=Float64)
#fermi energy
elseif contains(line, "Fermi")
out[:fermi] = parse(T, split(line)[5])
elseif contains(line, "lowest unoccupied") || contains(line, "highest occupied")
elseif contains(line, "lowest unoccupied") && contains(line, "highest occupied")
out[:fermi] = parse(T, split(line)[7])

elseif contains(line, "lowest unoccupied") || contains(line, "highest occupied")
out[:fermi] = parse(T, split(line)[5])
#setup for k_points
elseif contains(line, "celldm(1)")
alat_bohr = parse(T, split(line)[2])
Expand Down Expand Up @@ -148,7 +150,7 @@ function read_qe_output(filename::String, T=Float64)
for i = 1:length(out[:k_cart])
push!(eig_band, k_eigvals[i][i1])
end
push!(out[:bands], DFBand(out[:k_cart], out[:k_cryst], eig_band))
push!(out[:bands], DFBand(get(out, :k_cart,[[0.0,0.0,0.0]]), get(out, :k_cryst, [[0.0,0.0,0.0]]), eig_band))
end
end
return out
Expand Down Expand Up @@ -249,6 +251,21 @@ read_qe_vcrel(filename::String, T=Float64) = read_qe_output(filename, T) do x
# return out
# end
# end
function alat(control_blocks, pop=false)
sysblock = block(control_blocks, :system)
if sysblock == nothing
error("Could not resolve the alat!")
end
if haskey(sysblock.flags, :A)
alat = pop ? pop!(sysblock.flags, :A) : sysblock.flags[:A]
elseif haskey(sysblock.flags, celldm_1)
alat = pop ? pop!(sysblock.flags, celldm_1) : sysblock.flags[celldm_1]
alat *= conversions[:bohr2ang]
else
error("So far alat can be specified only through A and celldm(1).")
end
return alat
end

#TODO handle more fancy cells
function extract_cell!(control_blocks, cell_block)
Expand Down Expand Up @@ -414,14 +431,14 @@ function read_qe_input(filename, T=Float64::Type; exec="pw.x", run_command="", r
end

function write_block_data(f, data)
if typeof(data) <: Array{Vector{Float64},1} || typeof(data) <: Array{Vector{Float64},1} #k_points
if typeof(data) <: Vector{Vector{Float64}} || typeof(data) <: Vector{NTuple{4, Float64}} #k_points
for x in data
for y in x
write(f, " $y")
end
write(f, "\n")
end
elseif typeof(data) <: Array{Int,1}
elseif typeof(data) <: Vector{Int} || typeof(data) <: NTuple{6, Int}
for x in data
write(f, " $x")
end
Expand All @@ -447,8 +464,18 @@ function write_input(input::QEInput, structure, filename::String=input.filename)
write_flag(flag_data) = write_flag_line(f, flag_data[1], flag_data[2])
write_block(data) = write_block_data(f, data)


for block in input.control_blocks
blocks2file = QEControlBlock[]
c_block = getfirst(x -> x.name == :control, input.control_blocks)
s_block = getfirst(x -> x.name == :system, input.control_blocks)
if c_block != nothing
push!(blocks2file, c_block)
push!(blocks2file, s_block)
end
rest = filter(x -> x.name != :control && x.name != :system, input.control_blocks)
for r in rest
push!(blocks2file, r)
end
for block in blocks2file
write(f, "&$(block.name)\n")
if block.name == :system
nat = length(structure.atoms)
Expand Down

0 comments on commit 55bed15

Please sign in to comment.