Skip to content

Commit 55bed15

Browse files
committed
Fixes and Examples
1 parent b3da30f commit 55bed15

File tree

6 files changed

+166
-20
lines changed

6 files changed

+166
-20
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#This example requires cif2cell to be installed, and have it set in your PATH.
2+
using DFControl
3+
4+
#This example goes through how one would create a job from scratch, using a .cif file for the Structure.
5+
6+
#First go to your favourite Crystal structure database and download the .cif you want to use.
7+
#e.g. Si (F d -3 m :1) : http://www.crystallography.net/cod/9011998.cif
8+
9+
#We want to run an 'scf' and 'bands' calculation using QuantumEspresso.
10+
11+
12+
#Variables that will be passed to the `DFJob` constructor.
13+
14+
name = "Si" #this name will also be given to the Structure inside the DFJob
15+
local_dir = "/home/ponet/Documents/Si"
16+
server_dir = "/home/ponet/Si"
17+
run_command = "mpirun -np 24"
18+
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
19+
20+
pseudo_set = :pbesol #nonrelativistic calculation ( assumes you set up the pseudos, as demonstrated in the README)
21+
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.
22+
23+
#The header holds all the other information inside a job scriptfile that is not recognized as input and output.
24+
header = ["#SBATCH -N 1", "#SBATCH --ntasks-per-node=24",
25+
"#SBATCH --time=24:00:00", "#SBATCH -p defpart",
26+
"module load open-mpi/gcc/1.10.4-hfi", "module load mkl/2016.1.056"
27+
]
28+
29+
#The various calculations we want to run and the flags and data to pass to them are defined in two ways:
30+
# - calculation specific flags and data are associated with the calculation they belong to
31+
# - common flags can be defined as Pair{Symbol, Any} varargs at the end of the constructor call.
32+
scf_data = Dict(:k_points => (6, 6, 6, 1, 1, 1), :flags => [:verbosity => "'low'"])
33+
bands_data = Dict(:k_points => [(0.5, 0.5, 0.5, 100.),
34+
(0.0, 0.0, 0.0, 100.),
35+
(0.0, 0.5, 0.0, 1.)],
36+
:flags => [:verbosity => "'high'", :nbnd => 8])
37+
38+
calculations = [:scf => scf_data, :bands => bands_data] #the order here is the order in which the calculations will run!
39+
40+
#Now we load the cif file and create a `DFJob` from it.
41+
42+
job = DFJob(name, local_dir, "/home/ponet/Downloads/9011998.cif", calculations,
43+
:prefix => "'silicon'",
44+
:restart_mode => "'from_scratch'",
45+
:ecutwfc => 18.0,
46+
:mixing_mode => "'plain'",
47+
:mixing_beta => 0.7,
48+
:conv_thr => 1.0e-8,
49+
#kwargs
50+
server_dir = server_dir,
51+
bin_dir = bin_dir,
52+
run_command = run_command,
53+
header = header,
54+
pseudo_set = :pbesol,
55+
pseudo_specifier = pseudo_specifier
56+
)
57+
# An additional kwarg is `server=get_default_server()`, which is set to the server you have defined while following the setup in README.
58+
# This can ofcourse be changed to a different server.
59+
60+
#Now the job can be submitted to the server to run.
61+
submit_job(job)
62+
#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.
63+
#You can check the job.local_dir to see the input files and `job.tt` script.
64+
65+
#you can observe the slurm qstat by doing
66+
qstat()
67+
#or watch it by
68+
watch_qstat()
69+
#these default to run the commands on the default server
70+
71+
#hopefully everything went according to plan and we can watch our outputs
72+
outputs = pull_outputs(job)
73+
74+
#now the bandstructure can be plotted
75+
bands = read_qe_output(outputs[2])[:bands]
76+
#alt:
77+
bands = read_qe_bands_file(outputs[2])
78+
79+
fermi = read_qe_output(outputs[1])[:fermi]
80+
#alt:
81+
fermi = read_fermi_from_qe_output(outputs[1])
82+
using Plots
83+
84+
plot(bands, fermi=fermi)

examples/2edit_job_resubmit.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#This example assumes that you ran through the first one.
2+
# It will show how to load a job from a server, and change flags.
3+
4+
using DFControl
5+
6+
server_dir = "Si/"
7+
local_dir = "/home/ponet/Documents/Si"
8+
job = load_server_job(server_dir, local_dir)
9+
#shorthand:
10+
job = ldsj(server_dir, local_dir) #for other shorthands see DFControl/src/shorthands.jl
11+
12+
#change flags
13+
change_flags!(job, :ecutwfc => 25.0) #more `Pair{Symbol, Any}`'s can be given as varargs.
14+
#shorthand: chfls!
15+
#change_flags! will only go through already set flags to change them,
16+
#if you want to set new flags simply do (it can also be used to change already set flags):
17+
18+
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.
19+
20+
set_flags!(job, :ecutrho => 80., :diagonalization => "'david'")
21+
#shorthand: stfls!
22+
23+
#now we might not want to run all the calculations again.
24+
#one can change the job "flow":
25+
change_flow!(job, "scf" => false) #again, more `Pair{String, Bool}`'s can be given as varargs
26+
#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`.
27+
#If a job has calculations/inputs that don't need to run, their line will be commented out in `job.tt` script.
28+
29+
#now we can resubmit the job with the changed flags
30+
sbmj(job)

src/DFControl.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__precompile__(true)
1+
__precompile__()
22
module DFControl
33
# using Reexport
44
using RecipesBase
@@ -105,6 +105,7 @@ module DFControl
105105
export set_default_server
106106
export configure_default_pseudos
107107
export remove_default_pseudo_dir
108+
export get_default_pseudo
108109
export set_default_job_header
109110
export @add_default
110111
export load_defaults

src/defaults.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function get_default_pseudo_dir(pseudo_set)
122122
end
123123

124124
"""
125-
configure_default_pseudos!(server = get_default_server(), pseudo_dirs=get_default_pseudo_dirs())
125+
configure_default_pseudos(server = get_default_server(), pseudo_dirs=get_default_pseudo_dirs())
126126
127127
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.
128128
"""

src/job.jl

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,41 +33,38 @@ mutable struct DFJob
3333
end
3434

3535
#TODO implement abinit
36-
# function DFJob(job_name, local_dir, calculations::Array{Pair{Union{Symbol, String}, Dict},1}, atoms, cell_parameters=eye(3);
37-
function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStructure;
36+
function DFJob(job_name, local_dir, structure::AbstractStructure, calculations::Vector, common_flags...;
3837
server=get_default_server(),
3938
server_dir="",
4039
package=:qe,
4140
bin_dir="~/bin/",
4241
run_command="mpirun -np 24",
43-
common_flags=Dict{Symbol,Any}(),
4442
pseudo_set=:default,
4543
pseudo_specifier="",
4644
header=get_default_job_header())
4745

4846
@assert package==:qe "Only implemented for Quantum Espresso!"
4947
local_dir = form_directory(local_dir)
50-
job_atoms = convert_2atoms(atoms,pseudo_set=pseudo_set, pseudo_specifier=pseudo_specifier)
5148
job_calcs = DFInput[]
5249
if typeof(common_flags) != Dict
5350
common_flags = Dict(common_flags)
5451
end
55-
52+
bin_dir = form_directory(bin_dir)
5653
req_flags = Dict(:prefix => "'$job_name'",
5754
:outdir => "'$server_dir'",
5855
:ecutwfc => 25.)
5956
merge!(req_flags, common_flags)
6057
for (calc, data) in calculations
6158
calc_ = typeof(calc) == String ? Symbol(calc) : calc
6259
if in(calc_, [Symbol("vc-relax"), :relax, :scf])
63-
k_points = pop!(data, :k_points, [1, 1, 1, 0, 0, 0])
60+
k_points = get(data, :k_points, [1, 1, 1, 0, 0, 0])
6461
k_option = :automatic
6562
elseif calc_ == :nscf
66-
k_points = pop!(data, :k_points, (1, 1, 1))
63+
k_points = get(data, :k_points, (1, 1, 1))
6764
k_grid = gen_k_grid(k_points..., :nscf)
6865
k_option = :crystal
6966
elseif calc_ == :bands
70-
k_points = pop!(data, :k_points, [0., 0., 0., 1.])
67+
k_points = get(data, :k_points, [[0., 0., 0., 1.]])
7168
num_k = 0.0
7269
for point in k_points
7370
num_k += point[4]
@@ -77,7 +74,7 @@ function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStr
7774
end
7875
k_option = :crystal_b
7976
end
80-
flags = pop!(data, :flags, Dict{Symbol, Any}())
77+
flags = get(data, :flags, Dict{Symbol, Any}())
8178
push!(flags, :calculation => "'$(string(calc_))'")
8279
input_ = QEInput(string(calc_) * ".in",
8380
QEControlBlock[],
@@ -87,15 +84,16 @@ function DFJob(job_name, local_dir, calculations::Vector, structure::AbstractStr
8784
true)
8885
set_flags!(input_, req_flags..., print=false)
8986
set_flags!(input_, flags..., print=false)
90-
change_atoms!(input_, job_atoms, pseudo_set = pseudo_set, pseudo_specifier = pseudo_specifier, print=false)
9187
push!(job_calcs, input_)
9288
end
89+
out = DFJob(job_name, structure, job_calcs, local_dir, server, server_dir, header)
90+
change_atoms!(out, structure.atoms, pseudo_set = pseudo_set, pseudo_specifier= pseudo_specifier)
9391
return DFJob(job_name, structure, job_calcs, local_dir, server, server_dir, header)
9492
end
9593

96-
function DFJob(job_name, local_dir, calculations::Vector, ciffile::String; kwargs...)
94+
function DFJob(job_name, local_dir, ciffile::String, calculations::Vector, args...; kwargs...)
9795
structure = Structure(ciffile, name=job_name)
98-
return DFJob(job_name, local_dir, calculations, structure; kwargs...)
96+
return DFJob(job_name, local_dir, structure, calculations, args... ; kwargs...)
9997
end
10098

10199
function DFJob(job::DFJob, flagstoset...;
@@ -279,6 +277,12 @@ function push_job(job::DFJob, newfiles)
279277
if !ispath(job.local_dir)
280278
error("Please save the job locally first using save_job(job)!")
281279
else
280+
try
281+
run(`ssh -t $(job.server) touch $(job.server_dir * "tmp.in")`)
282+
run(`ssh -t $(job.server) rm $(job.server_dir * "tmp.in")`)
283+
catch
284+
run(`ssh -t $(job.server) mkdir $(job.server_dir)`)
285+
end
282286
for file in newfiles
283287
run(`scp $(job.local_dir * file) $(job.server * ":" * job.server_dir)`)
284288
end

src/qe/fileio.jl

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ function read_qe_output(filename::String, T=Float64)
5252
#fermi energy
5353
elseif contains(line, "Fermi")
5454
out[:fermi] = parse(T, split(line)[5])
55-
elseif contains(line, "lowest unoccupied") || contains(line, "highest occupied")
55+
elseif contains(line, "lowest unoccupied") && contains(line, "highest occupied")
5656
out[:fermi] = parse(T, split(line)[7])
5757

58+
elseif contains(line, "lowest unoccupied") || contains(line, "highest occupied")
59+
out[:fermi] = parse(T, split(line)[5])
5860
#setup for k_points
5961
elseif contains(line, "celldm(1)")
6062
alat_bohr = parse(T, split(line)[2])
@@ -148,7 +150,7 @@ function read_qe_output(filename::String, T=Float64)
148150
for i = 1:length(out[:k_cart])
149151
push!(eig_band, k_eigvals[i][i1])
150152
end
151-
push!(out[:bands], DFBand(out[:k_cart], out[:k_cryst], eig_band))
153+
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))
152154
end
153155
end
154156
return out
@@ -249,6 +251,21 @@ read_qe_vcrel(filename::String, T=Float64) = read_qe_output(filename, T) do x
249251
# return out
250252
# end
251253
# end
254+
function alat(control_blocks, pop=false)
255+
sysblock = block(control_blocks, :system)
256+
if sysblock == nothing
257+
error("Could not resolve the alat!")
258+
end
259+
if haskey(sysblock.flags, :A)
260+
alat = pop ? pop!(sysblock.flags, :A) : sysblock.flags[:A]
261+
elseif haskey(sysblock.flags, celldm_1)
262+
alat = pop ? pop!(sysblock.flags, celldm_1) : sysblock.flags[celldm_1]
263+
alat *= conversions[:bohr2ang]
264+
else
265+
error("So far alat can be specified only through A and celldm(1).")
266+
end
267+
return alat
268+
end
252269

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

416433
function write_block_data(f, data)
417-
if typeof(data) <: Array{Vector{Float64},1} || typeof(data) <: Array{Vector{Float64},1} #k_points
434+
if typeof(data) <: Vector{Vector{Float64}} || typeof(data) <: Vector{NTuple{4, Float64}} #k_points
418435
for x in data
419436
for y in x
420437
write(f, " $y")
421438
end
422439
write(f, "\n")
423440
end
424-
elseif typeof(data) <: Array{Int,1}
441+
elseif typeof(data) <: Vector{Int} || typeof(data) <: NTuple{6, Int}
425442
for x in data
426443
write(f, " $x")
427444
end
@@ -447,8 +464,18 @@ function write_input(input::QEInput, structure, filename::String=input.filename)
447464
write_flag(flag_data) = write_flag_line(f, flag_data[1], flag_data[2])
448465
write_block(data) = write_block_data(f, data)
449466

450-
451-
for block in input.control_blocks
467+
blocks2file = QEControlBlock[]
468+
c_block = getfirst(x -> x.name == :control, input.control_blocks)
469+
s_block = getfirst(x -> x.name == :system, input.control_blocks)
470+
if c_block != nothing
471+
push!(blocks2file, c_block)
472+
push!(blocks2file, s_block)
473+
end
474+
rest = filter(x -> x.name != :control && x.name != :system, input.control_blocks)
475+
for r in rest
476+
push!(blocks2file, r)
477+
end
478+
for block in blocks2file
452479
write(f, "&$(block.name)\n")
453480
if block.name == :system
454481
nat = length(structure.atoms)

0 commit comments

Comments
 (0)