Компиляция CalculiX Extras с поддержкой NVIDIA CUDA и методом Холецкого +9


CalculiX — довольно известный в узких кругах пре/постпроцессор и решатель для задач механики деформируемого твёрдого тела и задач механики жидкости и газа. Основной код полностью написан коллективом из двух человек — их имена «в вольной русской транскрипции» Гидо Донт (решатель), Клаус Виттиг (пре/пост). Дополнительно к основному коду можно найти удобный функциональный графический Launcher для подготовки расчётного файла. Чуть более подробная информация есть в русской Вики, несколько лет назад вбитая мною и ещё парой неравнодушных пользователей (ETCartman и Пруль, привет! К слову, могу подозревать, что ETCartman написал CalculiX Launcher, но это история, покрытая тайнами никнейнов).

С точки зрения рядового российского инженера, CalculiX не столь важное и необходимое в повседневной работе ПО, чтобы обращать на него внимание. Совсем иначе на CalculiX могут взглянуть научные сотрудники, ранее проводившие вычислительные эксперименты в Abaqus — CalculiX фактически является открытым клоном Abaqus, поскольку основатель у них один — Гидо Донт.

Большие два плюса CalculiX — кроссплатформенность и открытость исходников. Большие два минуса — практически полная неизвестность среди инженеров в СНГ и несколько меньший функционал по сравнению с Abaqus. Тем не менее, я решился сделать небольшую заметку о том, как получить бинарник CalculiX с поддержкой решателя на CUDA, в слабой надежде, что кому-нибудь на просторах СНГ данная информация пригодится.

Подразумеваю, что данную заметку прочтёт человек (или кибер, LOL), успевший познакомиться со структурой типового расчётного файла *.inp и принципом организации расчётов в CalculiX и знакомый с ОС Linux хотя бы на уровне «зашёл в консоль и знаю про apt-get», к тому же ГИК и заинтересованный в работе связки CalculiX и CUDA, ну или компиляции проекта с разложением Холецкого (cholmod).
Для начала, осмотритесь, что именно предлагается автором CalculiX Extras на страничке проекта, не пропустите ссылку на компиляцию проекта в Ubuntu. Внимательный читатель на странице автора поймёт, что скомпилить проект без пива и выходных подробных мануалов не получится. Поэтому я взял на себя смелость расшифровать все пробелы, которые автор CalculiX Extras любезно уместил между строк.

1. Необходимые библиотеки


Не знаю, как обстоят дела на дистрибутивах линукса кроме Mint, а в Mint 18 потребуется доустановить примерно следующий необходимый минимум библиотек для проекта:
binutils
cpp-5
gcc-5
gfortran-5
libstdc++6
libstdc++6:i386
autoconf
autoconf2.64
g++
g++-5
libarpack++2-dev
libarpack++2c2a
libbtf1.2.1
libcr0
libcsparse3.1.4
libcxsparse3.1.4
libhdf5-mpi-dev
libhdf5-mpich-10
libhdf5-openmpi-10
libhdf5-openmpi-dev
libldl2.2.1
metis
libmetis-dev
libmetis5
libmpich12
netcdf-bin
libnetcdf-c++4
libnetcdf-c++4-1
libnetcdf-c++4-dev
libopenblas-base
libopenblas-dev
libparpack2-dev
libstdc++-5-dev
libsuitesparse-dev
libexodusii5
libexodusii-dev
libnemesis3.

2. Драйверы видеокарты


Лучше всего установить свежий драйвер через утилиту Настройка-> Менеджер драйверов (в Linux Mint) и перезагрузиться.

Второй вариант — с оффициального сайта NVIDIA скачать для вашей видеокарты NVIDIA-driver с поддержкой CUDА и установить его:
i) `dpkg -i nvidia-diag-driver-local-repo-ubuntu1604_375.66-1_amd64.deb’ for Ubuntu
ii) `apt-get update`
iii) `apt-get install cuda-drivers`
iv) `reboot`

Также есть возможность поставить драйвер через менеджер пакетов Synaptic. Искать пакеты с именем NVIDIA.

3. Установка CUDA-Toolkit


Качаем 8-ю версию c официального сайта (7.5 у меня выдаёт ошибки при компиляции cudacusp.cu), запускать установку в консоли командой:

sudo ./cuda_8.0.61_375.26_linux.run --override

Драйвер из комплекта Toolkit не ставить. Ответы на вопросы установщика:

Do you accept the previously read EULA?
accept/decline/quit: accept

You are attempting to install on an unsupported configuration. Do you wish to continue?
(y)es/(n)o [ default is no ]: y

Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 375.26?
(y)es/(n)o/(q)uit: n

Install the CUDA 8.0 Toolkit?
(y)es/(n)o/(q)uit: y

Enter Toolkit Location
[ default is /usr/local/cuda-8.0 ]:

Do you want to install a symbolic link at /usr/local/cuda?
(y)es/(n)o/(q)uit: y

Install the CUDA 8.0 Samples?
(y)es/(n)o/(q)uit: y

Enter CUDA Samples Location
[ default is /home/usr ]:

Второй вариант установки — через менеджер пакетов Synaptic после обновления системы на свежую.

Третий вариант — как пишут разработчики NVIDIA:

Update the CUDA network repo keys using the following command
# sudo apt-key adv --fetch-keys developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
Add the CUDA network repo and update the package lists on your system to get new versions of the software and their dependencies.
# sudo sh -c 'echo «deb developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64 /» > /etc/apt/sources.list.d/cuda.list'
# sudo apt-get update
If you already have CUDA 8 installed on your instance and only need to update the NVIDIA driver, install the cuda-drivers meta-package. Then reboot the instance to complete the installation of the 375.66 NVIDIA driver.
# sudo apt-get -y --no-install-recommends install cuda-drivers
# sudo reboot
If you also need to install the CUDA toolkit, then install the cuda-toolkit-8-0 meta-package to download and install CUDA 8.
# sudo apt-get -y install cuda-toolkit-8-0

Refer to the Linux Installation Guide for CUDA Toolkit for more information on using runfiles or local installers to install CUDA on various Linux distributions. The guide is located at the following URL: (http://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html)

4. Необходимо скачать исходники CalculiX, ARPACK, CUDA cusp


Процесс сборки ARPACK подробно описан в статье. Да, она не маленькая, но ведь и вы — взрослые люди ) Разберётесь.

Папку cusp из архива CUDA cusp я поместил в хомяка (/home/usr в моём случае), саму либу версии 0.4.0! (это важно) взял тут.

На этом этапе вы можете проверить собираемость CalculiX без CUDA (см. статью).

5. Изменение системных переменных


Я добавил в /home/usr/.bashrc пути к библиотекам CUDA и путь к исходникам CalculiX:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/usr/CalculiX/ccx/src
PATH=$PATH:/usr/local/cuda/bin
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda/lib

6. Подключение библиотек


Единственная проблема у начинающих может возникнуть с указанием необходимых динамических библиотек, которых потребует объектный файл ccx_2.12.a при линковке библиотеки cudacusp.a. Для того, чтобы узнать требуемые библиотеки, войдите в каталог примеров CUDA cusp (/home/usr/cusp/examples в моём случае) и скомпилируйте какой-нибудь бинарник командой:

nvcc -o example example.cu -I/home/usr

Далее узнаёте список необходимых библиотек:

ldd example

В моём случае список данных либ в Makefile будет таким:

CUDACUSPLDFLAGS = -L/lib64 -l:libcufft_static.a -lstdc++ -lcuda -lcudart -lm -lgcc_s -lc -l:ld-linux-x86-64.so.2 -ldl -lpthread -lrt #-llinux-vdso

7. Патч CCX-Extras и сборка cudacusp.a


Ставим патчи как написано на страничке автора CCX-Extras. У вас появятся модифицированные исходники, в том числе файлы cudacusp.h, cudacusp.cu, cudacusp.thrustassembly.cu. Удалите cudacusp.cu (или переименуйте), скопируйте cudacusp.thrustassembly.cu -> cudacusp.cu. Откройте cudacusp.cu в текстовом редакторе и удалите слово «thrustassembly» из имени функции. Далее компилируем либу:

nvcc -O3 -lib -o cudacusp.a -c cudacusp.cu -arch=sm_20 -I. -I/home/usr -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L. -lstdc++ -lcuda -lcudart -DCUDACUSP

8. Сборка ccx


Изменяем Makefile (см. мой):
## This file is heavily modified from the Makefile distributed by with
## ccx. 

## pkg-config is used to pull all flags from local enviroment.  You
## must set this up.  Typically this would be defining
## PKG_CONFIG_PATH=$PKG_CONFIG_PATH:~/local/lib64/pkgconfig or
## similar.  You will also have to add .pc file for each library you
## use.  I did this because I have several machines with different
## library enviroments.  You could alternatively use compiler flags
## such as -L/path/to/lib -I/path/to/include -llib.  Examples of this
## on my distribution are in the comments below




################################################################################
################################################################################
##                                                                            ##
## Flags related to CPU, optimizations, etc                                   ##
## GPU based optimization later in the make file                              ##
##                                                                            ##
################################################################################
################################################################################

CC=gcc
FC=gfortran

## CFLAGS=-march=native -g -O0 ## debugging  -pg
## FFLAGS=-march=native -g -O0 ## debugging  -pg
## LDFLAGS += -g
## CFLAGS=-march=native -O2 -Wall ## conservative
## FFLAGS=-march=native -O2 -Wall ## conservative
CFLAGS=-march=native -O3 -Wall ## -flto ## aggressive -fprofile-generate -fprofile-use 
FFLAGS=-march=native -O3 -Wall ## -flto ## aggressive -fprofile-generate -fprofile-use 

## Integer8.  Note at least Arpack and Pardiso need to be compiled for
## Integer8 as well.  Spooles does not appear to be int8 according to Guido
## LONGLONG = -DLONGLONG
## CFLAGS  += $(LONGLONG)
## FFLAGS  += -fdefault-integer-8
## INTEXT = 64

## Other CCX Options
CFLAGS  += -DARCH="Linux" -DMATRIXSTORAGE 
LDFLAGS += 

## Multi Threaded and MPI
CFLAGS += -DUSE_MT
#CFLAGS += -DCALCULIX_MPI -fopenmp

## This is now default for calculix and relates to CFD
CFLAGS += -DNETWORKOUT




################################################################################
################################################################################
##                                                                            ##
## Flags related to CPU based solvers                                         ##
##                                                                            ##
################################################################################
################################################################################

## SPOOLES
CFLAGS  += -I/usr/include/spooles -I/usr/include/spooles/MT -DSPOOLES
LDFLAGS += -lspooles -lpthread
## CFLAGS  += `pkg-config --cflags spooles` -DSPOOLES
## LDFLAGS += `pkg-config --libs spooles`

## ARPACK
CFLAGS  += -DARPACK
LDFLAGS += -L/home/usr/ARPACK/ -l:libarpack_linux.a
## CFLAGS  += `pkg-config --cflags arpack$(INTEXT)` -DARPACK
## LDFLAGS += `pkg-config --libs arpack$(INTEXT)`

## TAUCS 
## CFLAGS  += -DTAUCS
## LDFLAGS += -ltaucs -lmetis

## LAPACK
## CFLAGS  += -I/usr/include/openblas
## LDFLAGS += -lreflapack -lopenblas
CFLAGS  += `pkg-config --cflags lapack$(INTEXT)`
LDFLAGS += `pkg-config --libs lapack$(INTEXT)`

## BLAS
## CFLAGS  += -I/usr/include/openblas
## LDFLAGS += -lopenblas
CFLAGS  += `pkg-config --cflags blas$(INTEXT)`
LDFLAGS += `pkg-config --libs blas$(INTEXT)`

## PARDISO
## CFLAGS  += -DPARDISO
## LDFLAGS += -L/home/pete/local/lib64/ -lpardiso -lgfortran -lpthread -lm -fopenmp
## CFLAGS  += `pkg-config --cflags pardiso` -DPARDISO
## LDFLAGS += `pkg-config --libs pardiso`



################################################################################
################################################################################
##                                                                            ##
## Flags related to GPU based solvers                                         ##
##                                                                            ##
################################################################################
################################################################################
# these libraries you can see when compile examples in cusp folder and see results of command "ldd <binary_name>"
CUDACUSPLDFLAGS = -L/lib64 -l:libcufft_static.a -lstdc++ -lcuda -lcudart -lm -lgcc_s -lc -l:ld-linux-x86-64.so.2 -ldl -lpthread -lrt #-llinux-vdso
CUDACUSPCFLAGS = -I/usr/include -I/usr/local/include -I/usr/local/cuda-8.0/include -I/usr/local/cuda-8.0/include/crt

## Flags for the gpu compiler
NVCCCFLAGS = $(CUDACUSPCFLAGS) -arch=sm_20 -I. -I/home/usr
NVCCLDFLAGS = -lib -L. -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -DCUDACUSP
NVCCLDFLAGS += $(CUDACUSPLDFLAGS)
## 
#NVCC=nvcc -O3 $(LONGLONG) `pkg-config --cflags cusp` `pkg-config --libs cusp` $(NVCCCFLAGS) # -Xcompiler -fopenmp
NVCC=nvcc -O3 $(LONGLONG) -o cudacusp.a -c cudacusp.cu $(NVCCCFLAGS) $(NVCCLDFLAGS) # -Xcompiler -fopenmp
# wrong         nvcc -O3 --compiler-options '-fPIC' -dc cudacusp.cu -arch=sm_20 -I. -I/home/usr -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L. -lstdc++ -lcuda -lcudart -DCUDACUSP
# wrong        nvcc -O3 -lib -o cudacusp.a cudacusp.a -arch=sm_20 -I. -I/home/usr-L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L. -lstdc++ -L. -lcuda -lcudart -DCUDACUSP
# wrong        cd /home/usr/cusp/examples/Solvers/
# right for compilation cudacusp.a:
# nvcc -O3 -lib -o cudacusp.a -c cudacusp.cu -arch=sm_20 -I. -I/home/usr -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L. -lstdc++ -lcuda -lcudart -DCUDACUSP

#nvcc -O3 -lib -o cudacusp.o -c cudacusp.cu -arch=sm_20 -I. -I/home/usr -L/usr/local/cuda/lib64 -L/usr/local/cuda/lib -L. -lstdc++ -lcuda -lcudart -DCUDACUSP
## CUDACUSP
## This is unique because it a template library rather than binary library
CFLAGS  += -I/home/usr/local/include -DCUDACUSP -I/home/usr/cusp -I.
LDFLAGS += -L. -L/usr/local/cuda-8.0/lib64/stubs -L/opt/cuda/lib64 -l:cudacusp.a
CFLAGS  += $(CUDACUSPCFLAGS)
LDFLAGS += $(CUDACUSPLDFLAGS)
## CFLAGS  += `pkg-config --cflags cusp` `pkg-config --libs cusp` -DCUDACUSP
## LDFLAGS += `pkg-config --libs cusp`

## CHOLDMOD
## This is unique because it can be CPU or GPU based, depending on how
## SuiteSparse was compiled.  Here it is assumed that SuiteSparse also
## uses CUDA
CFLAGS  += -DSUITESPARSE
LDFLAGS += -L/usr/local/cuda-8.0/lib64 -lcublas
LDFLAGS += -lcholmod -lmetis -lcolamd -lccolamd -lamd -lcamd -ldl -lcxsparse -lbtf
## LDFLAGS += `pkg-config --libs cublas$(INTEXT)`
## LDFLAGS += `pkg-config --libs cholmod$(INTEXT)`
## LDFLAGS += `pkg-config --libs metis$(INTEXT)`
## LDFLAGS += `pkg-config --libs colamd$(INTEXT)`
## LDFLAGS += `pkg-config --libs ccolamd$(INTEXT)`
## LDFLAGS += `pkg-config --libs amd$(INTEXT)`
## LDFLAGS += `pkg-config --libs camd$(INTEXT)`
## LDFLAGS += `pkg-config --libs ldl$(INTEXT)`
## LDFLAGS += `pkg-config --libs cxsparse$(INTEXT)`
## LDFLAGS += `pkg-config --libs btf$(INTEXT)`



################################################################################
################################################################################
##                                                                            ##
## Flags related to ExodusII output                                           ##
##                                                                            ##
################################################################################
################################################################################


## EXODUSII
CFLAGS  += -DEXODUSII
LDFLAGS += -lexoIIv2c -lnetcdf
## CFLAGS  += `pkg-config --cflags exodusii` -DEXODUSII
## LDFLAGS += `pkg-config --libs exodusii`




################################################################################
################################################################################
##                                                                            ##
## Recipes                                                                    ##
##                                                                            ##
################################################################################
################################################################################

## .cu file so not have a default implicit rule.  Define all implicit rules used.
.SUFFIXES: .o .c .cu

.c.o :
	$(CC) $(CFLAGS) -c $<
.f.o :
	$(FC) $(FFLAGS) -c $<
.cu.o:
	$(NVCC) -DCUDACUSP -c $<

include Makefile.inc

SCCXMAIN = ccx_2.12.c

## Define all the object file rules to identify dependencies
OCCXCU = $(SCCXCU:.cu=.o)
OCCXF = $(SCCXF:.f=.o)
OCCXC = $(SCCXC:.c=.o)
OCCXMAIN = $(SCCXMAIN:.c=.o)

## Link to math and standard c
CFLAGS += -lm -lc

ccx_2.12: $(OCCXMAIN) ccx_2.12.a
	./date.pl; 
	$(CC) $(CFLAGS) -c ccx_2.12.c $(LDFLAGS); $(FC) -Wall $(FFLAGS) -o $@ $(OCCXMAIN) ccx_2.12.a $(LDFLAGS)

ccx_2.12.a: $(OCCXF) $(OCCXC) # $(OCCXCU)
	ar vr $@ $?

clean:
	rm *.a *.o

Компилируем:


make
./ccx_2.12 --help

9. Тестируем ccx с поддержкой CUDA


Берём какой-нибудь пример со статическим анализом и проверяем решатели:

*STEP
*STATIC **- рабочий (быстрый) (это SPOOLES)
***STATIC, solver=CUDACUSP — рабочий (медленный)
***STATIC, solver=CHOLMOD — рабочий (быстрый)
***STATIC, solver=SUITESPARSEQR — рабочий (медленный)
***STATIC, solver=ITERATIVESCALING — рабочий (очень медленный)
***STATIC, solver=ITERATIVECHOLESKY — рабочий (очень медленный)
***STATIC, solver=SPOOLES — рабочий (быстрый)

Заключение


Решать статические тестовые задачки с помощью связки CalculiX + CUDA мне не понравилось — чересчур медленно, поскольку библиотека CUSP предназначена для разрешения уравнений вида A*X=B c разрежёнными матрицами большой размерности. Может быть связка гораздо эффективнее отрабатывает в задачах МЖГ. Но я не решаюсь опробовать данную сферу численного воздухоплавания — может быть читатель отважится?

P.S. Проверка работоспособности связки CalculiX + CUDA была моей личной инициативой и преследовала своей целью анализ возможности применения CalculiX Extras для задач обработки металлов давлением и штамповки листовых изделий. Что я могу сказать по результатам этой проверки? Облом-с, как в анекдоте с баша, «не для тебя цветочек рос», о чём меня, кстати, заранее предупредил Peter A. Gustafson (автор CalculiX Extras) в личном письме,
I note your doing metal forming. Fyi if you plan an explicit model, cuda is not implemented. Also, iterative solvers don't tend to perform better for this type of structure. This includes the static cuda solver implemented so far.

за что ему глубокая признательность. Хотя, ради спортивного интереса (и вопреки здравому смыслу) я всё же скомпилил проект, получив бурю зажигательных эмоций от процесса (в частности от перевода с японского).

С уважением к авторам CalculiX, CalculiX Extras, CalculiX Launcher и других дополнений,
а также к жителям Хабрахабр и Гиктаймс, с благодарностью к сообществу OpenSource, AlexKaz.
-->


К сожалению, не доступен сервер mySQL