[Samples] Add C++ OpenMP example

This commit is contained in:
Ray Speth 2017-01-28 15:07:15 -05:00
parent 3f6f580b25
commit 78d5809d6f
4 changed files with 119 additions and 8 deletions

View file

@ -248,6 +248,7 @@ defaults.noDebugLinkFlags = ''
defaults.warningFlags = '-Wall'
defaults.buildPch = False
env['pch_flags'] = []
env['openmp_flag'] = '-fopenmp' # used to generate sample build scripts
if 'gcc' in env.subst('$CC'):
defaults.optimizeCcFlags += ' -Wno-inline'
@ -270,11 +271,13 @@ elif env['CC'] == 'cl': # Visual Studio
defaults.warningFlags = '/W3'
defaults.buildPch = True
env['pch_flags'] = ['/FIpch/system.h']
env['openmp_flag'] = '/openmp'
elif 'icc' in env.subst('$CC'):
defaults.cxxFlags = '-std=c++0x'
defaults.ccFlags = '-vec-report0 -diag-disable 1478'
defaults.warningFlags = '-Wcheck'
env['openmp_flag'] = '-openmp'
elif 'clang' in env.subst('$CC'):
defaults.ccFlags = '-fcolor-diagnostics'

View file

@ -5,7 +5,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 11)
find_package(Threads REQUIRED)
@cmake_extra@
include_directories(@cmake_cantera_incdirs@)
link_directories(@cmake_cantera_libdirs@)

View file

@ -4,16 +4,27 @@ Import('env', 'build', 'install', 'buildSample')
# (subdir, program name, [source extensions])
samples = [
('combustor', 'combustor', ['cpp']),
('flamespeed', 'flamespeed', ['cpp']),
('kinetics1', 'kinetics1', ['cpp']),
('NASA_coeffs', 'NASA_coeffs', ['cpp']),
('rankine', 'rankine', ['cpp']),
('LiC6_electrode', 'LiC6_electrode', ['cpp'])
('combustor', 'combustor', ['cpp'], False),
('flamespeed', 'flamespeed', ['cpp'], False),
('kinetics1', 'kinetics1', ['cpp'], False),
('NASA_coeffs', 'NASA_coeffs', ['cpp'], False),
('rankine', 'rankine', ['cpp'], False),
('LiC6_electrode', 'LiC6_electrode', ['cpp'], False),
('openmp_ignition', 'openmp_ignition', ['cpp'], True)
]
for subdir, name, extensions in samples:
for subdir, name, extensions, openmp in samples:
localenv = env.Clone()
if openmp:
localenv.Append(CXXFLAGS=env['openmp_flag'], LINKFLAGS=env['openmp_flag'])
localenv['cmake_extra'] = """
find_package(OpenMP REQUIRED)
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS})
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS})
"""
else:
localenv['cmake_extra'] = ''
buildSample(localenv.Program, pjoin(subdir, name),
mglob(localenv, subdir, *extensions),
CPPPATH=['#include'],

View file

@ -0,0 +1,97 @@
// Ignition delay calculation with OpenMP. This example shows how to use OpenMP
// to run multiple reactor network calculations in parallel by using separate
// Cantera objects for each thread.
#include "cantera/zerodim.h"
#include "cantera/IdealGasMix.h"
#include <omp.h>
using namespace Cantera;
void run()
{
// The number of threads can be set by setting the OMP_NUM_THREADS
// environment variable before running the code.
int nThreads = omp_get_max_threads();
writelog("Running on {} threads\n\n", nThreads);
// Containers for Cantera objects to be used in different. Each thread needs
// to have its own set of linked Cantera objects. Multiple threads accessing
// the same objects at the same time will cause errors.
std::vector<std::unique_ptr<IdealGasMix>> gases;
std::vector<std::unique_ptr<IdealGasConstPressureReactor>> reactors;
std::vector<std::unique_ptr<ReactorNet>> nets;
// Create and link the Cantera objects for each thread. This step should be
// done in serial
for (int i = 0; i < nThreads; i++) {
gases.emplace_back(new IdealGasMix("gri30.xml", "gri30"));
reactors.emplace_back(new IdealGasConstPressureReactor());
nets.emplace_back(new ReactorNet());
reactors.back()->insert(*gases.back());
nets.back()->addReactor(*reactors.back());
}
// Points at which to compute ignition delay time
size_t nPoints = 50;
vector_fp T0(nPoints);
vector_fp ignition_time(nPoints);
for (size_t i = 0; i < nPoints; i++) {
T0[i] = 1000 + 500 * ((float) i) / ((float) nPoints);
}
// Calculate the ignition delay at each initial temperature using multiple
// threads.
//
// Note on 'schedule(static, 1)':
// This option causes points [0, nThreads, 2*nThreads, ...] to be handled by
// the same thread, rather than the default behavior of one thread handling
// points [0 ... nPoints/nThreads]. This helps balance the workload for each
// thread in cases where the workload is biased, e.g. calculations for low
// T0 take longer than calculations for high T0.
#pragma omp parallel for schedule(static, 1)
for (size_t i = 0; i < nPoints; i++) {
// Get the Cantera objects that were initialized for this thread
size_t j = omp_get_thread_num();
IdealGasMix& gas = *gases[j];
Reactor& reactor = *reactors[j];
ReactorNet& net = *nets[j];
// Set up the problem
gas.setState_TPX(T0[i], OneAtm, "CH4:0.5, O2:1.0, N2:3.76");
reactor.syncState();
net.setInitialTime(0.0);
// Integrate until we satisfy a crude estimate of the ignition delay
// time: time for T to increase by 500 K
while (reactor.temperature() < T0[i] + 500) {
net.step();
}
// Save the ignition delay time for this temperature
ignition_time[i] = net.time();
}
// Print the computed ignition delays
writelog(" T (K) t_ig (s)\n");
writelog("-------- ----------\n");
for (size_t i = 0; i < nPoints; i++) {
writelog("{: 8.1f} {: 10.3e}\n", T0[i], ignition_time[i]);
}
}
int main()
{
try {
run();
appdelete();
return 0;
} catch (CanteraError& err) {
// handle exceptions thrown by Cantera
std::cout << err.what() << std::endl;
std::cout << " terminating... " << std::endl;
appdelete();
return 1;
}
}