Class: CodeRunner::Trinity

Inherits:
Run::FortranNamelist
  • Object
show all
Includes:
ActualParameterValues, OutputFiles, TrinityGraphKits
Defined in:
lib/trinitycrmod/trinity.rb,
lib/trinitycrmod/trinity_gs2.rb,
lib/trinitycrmod/output_files.rb,
lib/trinitycrmod/check_parameters.rb,
lib/trinitycrmod/actual_parameter_values.rb,
lib/trinitycrmod/graphs.rb

Overview

This is a customised subclass of the CodeRunner::Run class which allows CodeRunner to run and analyse the multiscale gyrokinetic turbulent transport solver Trinity.

It  generates the Trinity input file, and both analyses the results and allows easy plotting of them. It also interfaces with the GS2 CodeRunner  module to allow analysis of the individual GS2 results if GS2 is being used as the flux code.

Defined Under Namespace

Modules: ActualParameterValues, OutputFiles, TrinityGraphKits

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TrinityGraphKits

#ang_mom_prof_graphkit, #eln_hflux_gb_prof_graphkit, #eln_hflux_prof_graphkit, #eln_pwr_prof_graphkit, #eln_temp_prof_graphkit, #fluxes_prof_graphkit, #ion_hflux_gb_prof_graphkit, #ion_hflux_prof_graphkit, #ion_pwr_prof_graphkit, #ion_temp_prof_graphkit, #lflux_gb_prof_graphkit, #nt_prof_graphkit, #pbalance_prof_graphkit, #prof_graphkit, #torque_prof_graphkit

Methods included from ActualParameterValues

#dflx_stencil_actual, #evolve_grads_only_actual, #fork_flag_actual

Methods included from OutputFiles

#fluxes_outfile, #info_outfile, #nt_outfile, #pbalance_outfile, #time_outfile, #view_outfiles

Class Method Details

.defaults_file_headerObject



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/trinitycrmod/trinity.rb', line 339

def self.defaults_file_header
	<<EOF1
############################################################################
#                                                                          #
# Automatically generated defaults file for the Trinity CodeRunner module  #
#                                                                          #
# This defaults file specifies a set of defaults for Trinity which are     #
# used by CodeRunner to set up and run Trinity simulations.                #
#                                                                          #
############################################################################

# Created: #{Time.now.to_s}   

@defaults_file_description = ""
EOF1
end

.get_input_help_from_source_code(source_folder) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/trinitycrmod/trinity.rb', line 287

def self.get_input_help_from_source_code(source_folder)
	source = get_aggregated_source_code_text(source_folder)
	rcp.namelists.each do |nmlst, hash|
		hash[:variables].each do |var, var_hash|

# 			next unless var == :w_antenna
			var = var_hash[:code_name] || var
			values_text = source.scan(Regexp.new("\\W#{var}\\s*=\\s*.+")).join("\n") 
			ep values_text
			values = scan_text_for_variables(values_text).map{|(v,val)| val} 
			values.uniq!
# 			ep values if var == :nbeta
			values.delete_if{|val| val.kind_of? String} if values.find{|val| val.kind_of? Numeric}
			values.delete_if{|val| val.kind_of? String and not String::FORTRAN_BOOLS.include? val} if values.find{|val| val.kind_of? String and String::FORTRAN_BOOLS.include? val}
# 			values.sort!
# 			ep var
# 			ep values
			sample_val = values[0]
			p sample_val
			help = values_text.scan(/ !(.*)/).flatten[0]
			p help
			#gets
			var_hash[:help] = help
			var_hash[:description] = help
			save_namelists

		end
	end
end

.use_new_defaults_file_with_gs2(name = ARGV[-3], trinity_input_file = ARGV[-2], gs2_input_file = ARGV[-1]) ⇒ Object

This function creates a new Trinity defaults file, with Trinity parameters taken from trinity_input_file, and GS2 parameters taken from gs2_input_file. The file is then moved to the CodeRunner central defaults location, the current folder is configured to use the defaults file.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/trinitycrmod/trinity_gs2.rb', line 16

def self.use_new_defaults_file_with_gs2(name = ARGV[-3], trinity_input_file = ARGV[-2], gs2_input_file = ARGV[-1])
   raise "Please specify a name, a trinity input file and a gs2 input file" if name == "use_new_gs2_defaults_file"
   defaults_filename = "#{name}_defaults.rb"
	tmp_filename = "#{name}_gs2tmp_defaults.rb"
	central_defaults_filename = rcp.user_defaults_location + "/" + defaults_filename
	FileUtils.rm(name + '_defaults.rb') if FileTest.exist?(name + '_defaults.rb')
	FileUtils.rm(central_defaults_filename) if FileTest.exist?(central_defaults_filename)
	FileUtils.rm(tmp_filename) if FileTest.exist?(tmp_filename)
	raise "Defaults file: #{central_defaults_filename} already exists" if FileTest.exist? central_defaults_filename


	make_new_defaults_file(name, trinity_input_file)
	CodeRunner::Gs2.make_new_defaults_file(name + '_gs2tmp', gs2_input_file)

	File.open(defaults_filename, 'a'){|file| file.puts <<EOF2
gs2_runs.each do |run|
run.instance_eval do
#{File.read(tmp_filename).gsub(/\A|\n/, "\n  ")}
end
end


EOF2
  
    }
	FileUtils.mv(defaults_filename, central_defaults_filename)
	FileUtils.rm(tmp_filename)
	CodeRunner.fetch_runner(C: rcp.code, m: (rcp.modlet? ? rcp.modlet : nil), D: name)

end

Instance Method Details

#check_flux_optionObject



21
22
23
24
25
# File 'lib/trinitycrmod/check_parameters.rb', line 21

def check_flux_option
	if @flux_option == "gs2"
	 error("subfolders must be .true. ") unless @subfolders and @subfolders.fortran_true?
	end
end

#check_geometeryObject



11
12
13
# File 'lib/trinitycrmod/check_parameters.rb', line 11

def check_geometery
	error( "Can't find geo_file #@geo_file (the path of geo file should be either absolute or set relative to the run folder #@directory). If you are not using a geometry file for this run please unset the parameter geo_file.") if @geo_file and not FileTest.exist? @geo_file
end

#check_parallelisationObject



15
16
17
18
19
# File 'lib/trinitycrmod/check_parameters.rb', line 15

def check_parallelisation
	error("nrad must be explicitly specified") unless @nrad
	error("Number of jobs: #{n_flux_tubes} must evenly divide the number of processors: #{actual_number_of_processors} when fork_flag is .true.") if fork_flag_actual.fortran_true? and not actual_number_of_processors%n_flux_tubes == 0

end

#check_parametersObject



3
4
5
6
7
8
9
# File 'lib/trinitycrmod/check_parameters.rb', line 3

def check_parameters

	check_geometery
	check_parallelisation
	check_flux_option

end

#evaluate_defaults_file(filename) ⇒ Object

Override standard CodeRunner method to allow for Gs2 variables



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/trinitycrmod/trinity_gs2.rb', line 63

def evaluate_defaults_file(filename)
	text = File.read(filename)
	text.scan(/^\s*@(\w+)/) do
		var_name = $~[1].to_sym
		next if var_name == :defaults_file_description
		unless rcp.variables.include? var_name or Gs2.rcp.variables.include? var_name
			warning("---#{var_name}---, specified in #{File.expand_path(filename)}, is not a variable. This could be an error")
		end
	end
	instance_eval(text)
end

#generate_component_runsObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/trinitycrmod/trinity.rb', line 175

def generate_component_runs
	#puts "HERE"
	@component_runs ||= []
	if @flux_option == "gs2"
	#puts "HERE"
  
		for i in 0...n_flux_tubes
			component = (@component_runs[i] ||= Gs2.new(@runner).create_component)
			component.component_runs = []
			#component.runner = nil
			#pp component; STDIN.gets
			#component.instance_variables.each{|var| puts var; pp var;  puts Marshal.dump(component.instance_variable_get(var)); STDIN.gets}
			#puts Marshal.dump(component); STDIN.gets
			#pp component; STDIN.gets
			#p component.class
			component.job_no = @job_no 
			component.status = @status
	#p ["HERE2", @component_runs.size, @component_runs[i]]
			#Dir.chdir(@directory) {
				compdir = "flux_tube_#{i+1}"
				Dir.chdir(compdir){component.process_directory} if FileTest.exist? compdir
			#}
			component.component_runs = []
			#@component_runs.push component
			component.real_id = @id
			#@gs2_run_list[i] = component
			#pp component; STDIN.gets
			#component.runner = nil
			#puts Marshal.dump(component); STDIN.gets
			#pp component; STDIN.gets
			#component.component_runs = []
		end
	end
end

#generate_gs2_input_filesObject

Writes the gs2 input files, creating separate subfolders for them if @subfolders is .true.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/trinitycrmod/trinity.rb', line 120

def generate_gs2_input_files
	# At the moment we must use subfolders
	for i in 0...n_flux_tubes
		#gs2run = gs2_run(:base).dup
		#gs2_run(i).instance_variables.each do |var|
			#gs2run.instance_variable_set(var, gs2_run(i).instance_variable_get(var))
		#end
		gs2run = gs2_runs[i]
		#p ['i',i]
		if @subfolders and @subfolders.fortran_true?
			gs2run.directory = @directory + "/flux_tube_#{i+1}"
			FileUtils.makedirs(gs2run.directory)
			gs2run.relative_directory = @relative_directory + "/flux_tube_#{i+1}"
			gs2run.restart_dir = gs2run.directory + "/nc"
		else
			gs2run.directory = @directory
			gs2run.relative_directory = @relative_directory
		end
		gs2run.run_name = @run_name + (i+1).to_s
		gs2run.nprocs = @nprocs
		if i==0
			block = Proc.new{ingen}
		else
			block = Proc.new{}
		end
		Dir.chdir(gs2run.directory){gs2run.generate_input_file(&block); gs2run.write_info}

		### Hack the input file so that gs2 gets the location of 
		# the restart dir correctly within trinity
		if @subfolders and @subfolders.fortran_true?
			infile = gs2run.directory + "/" + gs2run.run_name + ".in"
			text = File.read(infile)
			File.open(infile, 'w'){|f| f.puts text.sub(/restart_dir\s*=\s*"nc"/, "restart_dir = \"flux_tube_#{i+1}/nc\"")}
		end
	end
end

#generate_input_fileObject

This is a hook which gets called just before submitting a simulation. It sets up the folder and generates any necessary input files.



87
88
89
90
91
92
# File 'lib/trinitycrmod/trinity.rb', line 87

def generate_input_file
	  @run_name += "_t"
		check_parameters
		write_input_file
		generate_gs2_input_files if @flux_option == "gs2"
end

#get_2d_array_float(outfile, column_header, index_header) ⇒ Object

Return a two-dimensional array of floatingpoint numbers from the file ending in outfile,

from the column whose header matches column_header,  indexed by index_header. See
TextDataTools::Column::DataFile for more information. Outfile is a symbol, use e.g. :nt 
for data from 'run_name.nt'.


44
45
46
47
48
# File 'lib/trinitycrmod/output_files.rb', line 44

def get_2d_array_float(outfile, column_header, index_header)
	cache[:array_2d] = {} unless [:Complete, :Failed].include? @status
	cache[:array_2d] ||= {}
	cache[:array_2d][[outfile, column_header, index_header]] ||= send(outfile + :_outfile).get_2d_array_float(column_header, index_header)
end

#get_completed_timestepsObject



264
265
266
267
268
269
270
# File 'lib/trinitycrmod/trinity.rb', line 264

def get_completed_timesteps
	Dir.chdir(@directory) do
		@completed_timesteps = time_outfile.exists? ? 
			time_outfile.get_1d_array_integer(/itstep/).max :
			0
	end
end

#get_global_resultsObject



273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/trinitycrmod/trinity.rb', line 273

def get_global_results
	@fusionQ = info_outfile.get_variable_value('Q').to_f
	@pfus = info_outfile.get_variable_value(/fusion\s+power/i).to_f
	@pnet = info_outfile.get_variable_value(/net\s+power/i).to_f
	@aux_power = info_outfile.get_variable_value(/aux.*\s+power/i).to_f
	@alpha_power = info_outfile.get_variable_value(/alpha\s+power/i).to_f
	@rad_power = info_outfile.get_variable_value(/radiated\s+power/i).to_f
	@ne0 = info_outfile.get_variable_value(/core\s+density/i).to_f
	@ti0 = info_outfile.get_variable_value(/core\s+T_i/i).to_f
	@te0 = info_outfile.get_variable_value(/core\s+T_e/i).to_f
	@omega0 = info_outfile.get_variable_value(/core\s+omega/i).to_f
	#p 'send(fusionQ)', send(:fusionQ)
end

#get_statusObject



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/trinitycrmod/trinity.rb', line 246

def get_status
	if @running
		get_completed_timesteps
		if completed_timesteps == 0
			@status = :NotStarted
		else
			@status = :Incomplete
		end
	else
		get_completed_timesteps
		if File.read(output_file) =~/trinity\s+finished/i
			@status = :Complete
		else
			@status = :Failed
		end
	end
end

#graphkit(name, options) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/trinitycrmod/graphs.rb', line 91

def graphkit(name, options)
	[:t].each do |var|
		#ep 'index', var
		if options[var].class == Symbol and options[var] == :all
			options[var] = list(var).values
		elsif options[var+:_index].class == Symbol and options[var+:_index] == :all
			#ep 'Symbol'
			options[var+:_index] = list(var).keys
		end
		if options[var].class == Array
			return options[var].map{|value| graphkit(name, options.dup.absorb({var =>  value}))}.sum
		elsif options[var+:_index].class == Array
			#ep 'Array'
			return options[var+:_index].map{|value| graphkit(name, options.dup.absorb({var+:_index =>  value}))}.sum
		end
		if options[var].class == Symbol and options[var] == :max
			options[var] = list(var).values.max
		elsif options[var+:_index].class == Symbol and options[var+:_index] == :max
			ep 'Symbol'
			options[var+:_index] = list(var).keys.max
		end
	end
	if meth = TrinityGraphKits.instance_methods.find{|m| m.to_s == name + '_graphkit'}
		return send(meth, options)
	else
		raise	"GraphKit not found: #{name}"
	end	
end

#gs2_runsObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/trinitycrmod/trinity_gs2.rb', line 47

def gs2_runs
	#puts "2@COMMMMMMMMMMMMMPOOOOOOOOOOOOOONNNETN", @component_runs
	generate_component_runs if not (@component_runs and @component_runs.size > 0)
	#p ["@COMMMMMMMMMMMMMPOOOOOOOOOOOOOONNNETN", @component_runs]
	@component_runs
	#@gs2_run_list ||= {}
	#raise TypeError.new("@runner is nil") if @runner.nil?
	#@gs2_run_list[key] ||= Gs2.new(@runner)
	##if key != :base
		##raise "key in gs2_run must be either :base or an integer" unless key.kind_of? Integer
		##@gs2_run_list[key] ||= @gs2_run_list[:base].dup
	##end
	#@gs2_run_list[key]
end

#input_file_headerObject



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/trinitycrmod/trinity.rb', line 317

def input_file_header
	<<EOF
!==============================================================================
!  		Trinity INPUT FILE automatically generated by CodeRunner 
!==============================================================================
!
!  Trinity is a multiscale turbulent transport code for fusion plasmas.
!  
!  	See http://gyrokinetics.sourceforge.net
!
!  CodeRunner is a framework for the automated running and analysis 
!  of large simulations. 
!
!  	See http://coderunner.sourceforge.net
!  
!  Created #{Time.now.to_s}
!      by CodeRunner version #{CodeRunner::CODE_RUNNER_VERSION.to_s}
!
!==============================================================================

EOF
end

#list(var) ⇒ Object

Returns a hash of the specified dimension in the form value where index is 1-based Dimension can be: :t :rho :rho_cc



55
56
57
58
59
60
61
62
# File 'lib/trinitycrmod/output_files.rb', line 55

def list(var)
	case var
	when :t
		hash  = {}
		get_2d_array_float(:nt, /1:\s+time/, /1:\s+time/).map{|arr| arr[0]}.each_with_index{|t,i| hash[i+1] = t}
		hash
	end
end

#n_flux_tubesObject

The number of separate flux tube results needed for the jacobian



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/trinitycrmod/trinity.rb', line 96

def n_flux_tubes
	d1 = dflx_stencil_actual - 1
	ngrads =d1 * case @grad_option
								when "tigrad", "ngrad", "lgrad"
									1
								when "tgrads"
									2
								when "ltgrads", "ntgrads"
									3
								when "all"
									4
								else
									raise "unknown grad_option: #@grad_option"
								end
	if evolve_grads_only_actual.fortran_true?
		njac = ngrads + 1
	else
		njac = 2*ngrads+1
	end
	#p 'nraaad', @nrad
	(@nrad-1) * njac
end

#parameter_stringObject

Parameters which follow the Trinity executable, in this case just the input file.



168
169
170
# File 'lib/trinitycrmod/trinity.rb', line 168

def parameter_string
	@run_name + ".trin"
end

#parameter_transitionObject



172
173
# File 'lib/trinitycrmod/trinity.rb', line 172

def parameter_transition
end

A hook which gets called when printing the standard run information to the screen using the status command.



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/trinitycrmod/trinity.rb', line 64

def print_out_line
	#p ['id', id, 'ctd', ctd]
	#p rcp.results.zip(rcp.results.map{|r| send(r)})
	name = @run_name
	name += " (res: #@restart_id)" if @restart_id
	name += " real_id: #@real_id" if @real_id
	beginning = sprintf("%2d:%d %-60s %1s:%2.1f(%s) %3s%1s",  @id, @job_no, name, @status.to_s[0,1],  @run_time.to_f / 60.0, @nprocs.to_s, percent_complete, "%")
	if ctd
		beginning += sprintf("Q:%f, Pfusion:%f MW, Ti0:%f keV, Te0:%f keV, n0:%f x10^20", fusionQ, pfus, ti0, te0, ne0)
	end
	beginning += "  ---#{@comment}" if @comment
	beginning
end

#process_directory_code_specificObject

This method, as its name suggests, is called whenever CodeRunner is asked to analyse a run directory. This happens if the run status is not :Complete, or if the user has specified recalc_all(-A on the command line) or reprocess_all (-a on the command line).



236
237
238
239
240
241
242
243
244
# File 'lib/trinitycrmod/trinity.rb', line 236

def process_directory_code_specific
	get_status
	#p ['id is', id, 'ctd is ', ctd]
	if ctd
		get_global_results 
	end
	#p ['fusionQ is ', fusionQ]
	@percent_complete = completed_timesteps.to_f / ntstep.to_f * 100.0
end

#saveObject



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/trinitycrmod/trinity.rb', line 211

def save
	#@gs2_run_list.values.each{|r| r.runner = nil; r.component_runs = []} if @gs2_run_list.kind_of? Hash
	super
	#@gs2_run_list.values.each{|r| r.runner = @runner} if @gs2_run_list.kind_of? Hash

	#logf(:save)
	#raise CRFatal.new("Something has gone horribly wrong: runner.class is #{@runner.class} instead of CodeRunner") unless @runner.class.to_s == "CodeRunner"
	#runner, @runner = @runner, nil
	#@system_triers, old_triers = nil, @system_triers
	#@component_runs.each{|run| run.runner = nil; run.component_runs = []} if @component_runs
	##@component_runs.each{|run| run.runner = nil} if @component_runs
##   logi(self)
	##pp self
  ##@component_runs.each{|ph| ph.instance_variables.each{|var| puts var; pp ph.instance_variable_get(var); STDIN.gets;  puts ph.Marshal.dump(instance_variable_get(var))}} if @component_runs
  ##instance_variables.each{|var| puts var;  instance_variable_get(var);  puts Marshal.dump(instance_variable_get(var)); STDIN.gets}
	#Dir.chdir(@directory){File.open(".code_runner_run_data", 'w'){|file| file.puts Marshal.dump(self)}}
	#@runner = runner
	#@component_runs.each{|run| run.runner = runner} if @component_runs
	#@system_triers = old_triers
end

#vim_outputObject Also known as: vo



157
158
159
# File 'lib/trinitycrmod/trinity.rb', line 157

def vim_output
	system "vim -Ro #{output_file} #{error_file} #@directory/#@run_name.error #@directory/#@run_name.out "
end

#write_input_fileObject

This command uses the infrastructure provided by Run::FortranNamelist, provided by CodeRunner itself.



163
164
165
# File 'lib/trinitycrmod/trinity.rb', line 163

def write_input_file
	File.open(@run_name + ".trin", 'w'){|file| file.puts input_file_text}
end