суббота, 26 января 2013 г.

Cовместное использование языков Си и Фортран.

В UNIX системах языки Си и Фортран могут использоваться вместе, так как между этими языками возможны прямые вызовы функций. При этом, правда, необходимо тщательно учитывать совместимость типов передаваемых аргументов. Обычно соответствие между типами в Си и Фортране можно представить так:
signed char    INTEGER*1
short               INTEGER*2
int                   INTEGER
long                INTEGER*4
float                REAL
double            DOUBLE PRECISION
void sub_        SUBROUTINE SUB()
float  fun_()     REAL FUNCTION FUN
Также следует помнить о следующем: 
  • в Фортране аргументы в функции всегда передаются ссылками;
  • В Си массивы передаются через адрес;
  • Порядок индексации многомерных массивов различен для Си и Фортрана - в Си элементы массива располагаются построчно, в Фортране - по столбцам;
  • Имена функций в Фортране имеют в своем конце "скрытый" знак подчеркивания '_' (его нет в исходном тексте, но он добавляется компилятором), поэтому, если некая фунция вызывается из Фортрана как fun(), то эта же функция из Си вызывается как fun_() ; 
  • В языке Си длина строки определяется положением нулевого байта, в Фортране же строки имеют фиксированную длину. Поэтому при передаче строки из Си кода в Фортран необходимо передавать также ее длину. В случае же передачи строки из Фортран кода в Си необходимо добавить нуль в конец строки;
Рассмотрим два случая: когда си код вызывается из фортрана и , наоборот, когда из фортран кода вызывается си код.
Файл cCode1.c:
#include<stdio.h>
void
c_function_(){
     printf("Hello from C code!\n");
}
 Файл fortranCode1.f90:
program hello
    implicit none
    call c_function()
    write (*,*)"Hello from FORTRAN code!"
end program hello
 Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode1.o -c fortranCode1.f90
#gcc -O2 -g -o cCode1.o -c cCode1.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode1.o cCode1.o -o hello1
#./hello1
Нужно, чтобы присутствовала библиотека libgfortran.so
 /usr/lib/gcc/i486-linux-gnu/4.7/ - это путь, по которомуона у меня лежит. У вас может быть другой путь.
Обратный случай:
Файл cCode2.c:
#include<stdio.h>
void
main(){
     fortran_function_();
     printf("Hello from C code!\n");
Файл fortranCode2.f90:
subroutine fortran_function
    implicit none
    write (*,*)"Hello from FORTRAN code!"
end subroutine fortran_function
Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode2.o -c fortranCode2.f90
#gcc -O2 -g -o cCode2.o -c cCode2.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode2.o cCode2.o -o hello2
#./hello2
Теперь сделаем вызов функции с передачей параметров разных типов.
Файл cCode3.c:
#include<stdio.h>
void
c_function_(signed char* a1, short* a2, int* a3, long int* a4){
     printf("in called c function: \n%d\t%d\t%d\t%ld\n", *a1, *a2, *a3, *a4);
}
 Файл fortranCode3.f90:
program hello
    implicit none
    integer*1 a1
    integer*2 a2
    integer*4 a3
    integer*8 a4
    a1=1
    a2=22
    a3=333
    a4=4444
    call c_function(a1, a2, a3, a4)
end program hello
 #gfortran -O2 -g -o fortranCode3.o -c fortranCode3.f90
#gcc -O2 -g -o cCode3.o -c cCode3.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode3.o cCode3.o -o hello3
#./hello3
 Файл cCode4.c:
#include<stdio.h>
void
main(){
     signed char a1 = 1;
     short            a2 = 22;
     int                 a3 = 333;
     long              a4 = 4444;
     fortran_function_(&a1, &a2, &a3, &a4);
Файл fortranCode4.f90:
subroutine fortran_function(f1, f2, f3, f4)
    implicit none
    integer*1 f1
    integer*2 f2
    integer*4 f3
    integer*4 f4
    write (*,100)f1,f2,f3,f4
100 format(4i5)
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode4.o -c fortranCode4.f90
#gcc -O2 -g -o cCode4.o -c cCode4.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode4.o cCode4.o -o hello4
#./hello4
Теперь продемонстрируем передачу символьных строк из Си в Фортран и обратно.

Файл cCode5.c:
#include<stdio.h>
void
     c_function_(char* string){
     printf("%s\n", string);
}
 Файл fortranCode5.f90:
program hello
    implicit none
    character*37 string
    string="Created in fortran, outputed from C!"
    string(37:37)=char(0)
    call c_function(string)
end program hello
#gfortran -O2 -g -o fortranCode5.o -c fortranCode5.f90
#gcc -O2 -g -o cCode5.o -c cCode5.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode5.o cCode5.o -o hello5
#./hello5 
Теперь наоборот. Сформируем строку в Си, а напечатаем в Фортране.
Файл cCode6.c:
#include<string.h>
void
main(){
     char string[37];
     int length = sizeof(string);
     strncpy(string, "Created in C, outputed from Fortran!", length);
     fortran_function_(string, &length);
}
Файл fortranCode6.f90:
subroutine fortran_function(string, length)
    implicit none
    character*(*) string
    integer length
    write(*,100)string(1:length)
100 format(a)
    return
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode6.o -c fortranCode6.f90
#gcc -O2 -g -o cCode6.o -c cCode6.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode6.o cCode6.o -o hello6
#./hello6
Все примеры протестированы в Debian Wheezy.

среда, 16 января 2013 г.

sed: убираем лишнее

При работе с большими текстовыми файлами, хранящими данные для построения графиков, очень часто не нужен весь объем хранимой  информации. Тут на помощь может прийти утилита sed.
Чтобы удалить каждую 5-ю, например, строку, можно сделать так: 
sed -n '0~5d' bigdata.txt > lessdata.txt
А что если мы хотим не удалить каждую 5-ю, а сохранить, удалив остальные строки? Тогда так:
sed -n '0~5p' bigdata.txt > lessdata.txt
Следующая команда делает то же плюс сохраняет первую и последнюю строки:
sed -n '1p;0~5p;$p' bigdata.txt > lessdata.txt 

среда, 9 января 2013 г.

Gnuplot: линейная аппроксимация

Пусть у нас имеется текстовый файл myData.dat состоящий из двух колонок цифр и мы хотим нарисовать два графика: первый, изображенный символами (точками), собственно данные; второй, представленный линией, которая и является линейной аппроксимацией этих данных. Создадим файл myApproximation.plt следующего содержания:
my_linear_fit(x)=a*x+b
fit my_linear_fit(x) 'myData.dat' via a,b
plot 'myData.dat'     title 'my data', my_linear_fit(x) title 'approximation of my data' 
И запустим gnuplot из директории, в которой создали этот файл и введем команду:
>load 'myApproximation.plt'
Для задания диапазонов абсциссы и ординаты пользуем такие команды:
>set xrange [0:100]
>set yrange[0:]
Цифры даны для примера.

Установка сетевого принтера в Debian GNU/Linux 7.0 (wheezy)

После установки (в моем случае) Debian wheezy штатные утилиты гнома почему-то не устанавливали (а, возможно, и не должны) сетевого принтера. Но это не есть большой трудностью. Достаточно доустановить пакет system-config-printer. И после запуска кочанды system-config-printer из-под администратора легко найти и подсоединить принтер

Gnuplot: вывод в несколько окон

Если мы делаем графики в Gnuplot, то по умолчанию вывод этих графиков делается в окно с заголовком "Gnuplot(window id:0)". В других операционных системах заголовок, возможно, другой. Я использую Debian GNU/Linux 7.0 (wheezy). Но суть не в этом. Итак. Если мы дадим команду replot или plot, но с другими чем в предыдущем plot опциями, то наш предыдущий график будет затираться новым. Но что, если я хочу нарисовать еще один график не уничтожая предыдущего? Можно рисовать следующие графики в новом окне. Делается это командой:
>set terminal wxt n
где n - это некое число: 1,2,3 и т.д. Соответственно новое окно будет выводиться с заголовком "Gnuplot(window id:n)".

пятница, 4 января 2013 г.

Два монитора на компьютере с Debian

Хорошо, если у нас есть ноутбук с Debian wheezy. А что если у нас есть второй монитор и мы хотим его подсоединить к нашему ноутбуку? В моем случае второй монитор подсоединился автоматически, но при этом не только на нем вывод был с плохой разрешающей способностью, но и на экране самого ноутбука качество изображения изменилось не вbлучшую сторону. Вобщем встал вопрос: как "правильно" подсоединить второй монитор к нашему ноутбуку? Выполним программу xandr:
#xrandr
В моем случае вывод был такой:
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192
LVDS1 connected (normal left inverted right x axis y axis)
   1366x768       60.0 +
   1360x768       59.8     60.0  
   1024x768       60.0  
   800x600        60.3     56.2  
   640x480        59.9  
VGA1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 509mm x 286mm
   1920x1080      60.0*+
   1280x1024      75.0     60.0  
   1152x864       75.0  
   1024x768       75.1     60.0  
   800x600        75.0     60.3  
   640x480        75.0     60.0  
   720x400        70.1  
HDMI1 disconnected (normal left inverted right x axis y axis)
DP1 disconnected (normal left inverted right x axis y axis)
Достаточно прозрачный вывод. Если выполнить программу xrandr со следующими параметрами (их значения выбираем из вывода предыдущей команды):
#xrandr --output VGA1 --mode 1920x1080 --output LVDS1 --off
то графический вывод будет осуществляться только на присоединенный монитор. Если выполнить команду:
#xrandr --output VGA1 --off --output LVDS1 --mode 1366x768 --pos 0x0
то вывод будет выполняться только на экран ноутбука. Общая идея понятна. Теперь мы хотим следующее. При включении компьютера, если подсоединен второй монитор, нам надо, чтобы включался только этот второй моитор. Если второго монитора нет, то пусть включается только (а что ж еще?) монито ноутбука. Дя этого создаем файл /etc/X11/Xsession.d/45custom_xrandr со следующим содержанием (он запускается при запуске иксов):
xrandr | grep VGA1 | grep " connected "
if [$? -eq 0]; then
      # Внешний монитор отключен
      # Если мы хотим два показывающих монитора
      # xrandr --output VGA1 --mode 1920x1080 --pos 0x0 --output LVDS1 --mode 1366x768 --pos 0x0
      # Если мы хотим включенный только внешний монитор
      xrandr --output VGA1 --mode 1920x1080 --output LVDS1 --off
      if [$? -ne 0]; then
           # Если что-то не так
           xrandr --output LVDS1 --mode auto --output VGA1 --off
      fi
else
      # Внешний монитор не подключен
      xrandr --output LVDS1 --mode 1366x768 --output VGA --off
fi
Вот и все. Написано по материалам, взятым отсюда.