2017년 11월 22일 수요일

Puzzle: 구름의 그림자

구름의 그림자는 실제 구름의 크기와 비교할 때 더 클까,작을까, 아니면 같을까?
다음 중 어느 것이 옳을까?

(1) 태양으로 부터 오는 빛은 넓게 퍼진다. 따라서, 구름의 그림자는 실제 구름보다 더 클 것이다.

(2) 태양은 매우 멀리 떨어져 있기 때문에 지구에 오는 빛은 거의 평행하게 들어 온다. 따라서, 구름의 그림자는 실제의 크기와 같을 것이다.

(3) 태양은 작아 보이지만, 실제로는 매우 크다. 따라서, 구름의 그림자는 실제 구름보다 작을 것이다.

여기서, 빛은 직진한다고 생각하고, 빛의 반사, 산란등에 의한 효과는 무시하자.
그림자는 태양에서 오는 어떤 빛도 도달하지 않는 부분을 말한다.
또한, 위도에 따른 효과도 고려하지 말고, 정오에 태양이 머리위에 있는 경우만 생각하자.

-------------------------------------------------------------------------------------------------
먼저 구름위에 비친 태양 빛이 퍼지는 것처럼 보이는 것은 원근에 의한 효과이다.
예를 들어 평행하게 직선으로 놓여진 철길이라도 멀리에서 보면, 한점에서 퍼져 나오는
것처럼 보인다. 마찬가지로 직선으로 빛이 지나가더라도 관찰자를 중심으로 한쪽은
빛이 한 점에서 퍼져나오는 것처럼, 반대쪽은 한 곳으로 빛이 모이는 것처럼 보인다.
따라서, 빛이 평행하게 오는 한
구름의 그림자가 실제 구름보다  커지지는 않는다. (빛이 사선으로 내리쬐지 않는한.)

이해하기 쉽도록 전등과 물체, 그리고 스크린에 생기는 물체의 그림자를 생각해보자.
극단적인 경우를 생각해서, 광원보다 매우 큰 물체의 경우에는 언제나 스크린에 생기는 그림자는 실제 크기와 같거나 더 클 것임을 알 수 있다. (이때는 빛이 평행하지 않다.)
극단적으로 물체의 크기가 매우 작은 경우에는, 스크린이 물체의 바로 뒤에 있을 때를 제외하면 그림자의 크기는 언제나 실제 크기보다 작을 것이다. 심지어, 광원에 물체를 가깝게 두고, 스크린과의 거리가 먼 경우에는 아예 그림자가 생기지 않는 경우를 생각할 수 있다.

여기서 중요한 것은 광원의 크기를 고려하면, 우리가 보는 그림자는 한 점에서 오는 빛에 의한 그림자가 아니라, 여러점에서 오는 빛의 중첩이라는 것이다. 즉, 스크린의 어떤 점에 대해, 광원에서 오는 빛중 일부는 그림자를 만들 것이고, 일부는 그림자를 만들지 않는다. 모든 빛이 도달하지 않는 곳이 가장 어두울 것이고, 어떤 부분은 덜 어둡거나, 밝을 것이다.

태양은 지구보다 크고 멀리 떨어져 있으므로 구름의 그림자는 언제나
실제 구름의 크기보다 작다는 것을 알 수 있다.

어림계산을 해보자. 지구에서 태양까지의
거리는 대략 150 million km 이고, 태양의 지름은 0.7 million km 이다. 따라서,지구에서 보는 태양의 시야각은 대략 0.25 도 정도가 된다. ( tan(theta)~0.7/150 ) 지구의 크기는 태양까지의 거리나 태양의 크기에 비해 매우 작으므로, 지상으로부터의 높이 차이와 상관없이
태양의 시야각은 대략 0.25 라고 볼 수 있다. 지상위에서의 높이 차이는 구름의 높이나 태양까지의 거리에 비해 작을 것이므로, H:150 ~ (구름의 크기): 0.7 인 관계로 부터,
H ~ (구름의 크기)*4 를 만족 시킬 때 지상에서는 구름의 그림자가 한 점으로 나타나게 된다. 만약 구름의 높이가 H > (구름의 크기)*4 이라면, 지상에서 구름의 그림자는 나타나지 않게 된다.








2017년 11월 21일 화요일

포인터와 레퍼런스(C++)

C 와 C++보다는 Fortran, Python을 주로 쓰다보니
여전히 pointer 나 reference 를 사용하는 C, C++은 어렵게 느껴진다.
기본적인 차이는 Fortran은 call by reference가 기본이라
사실은 언제나 pointer를 사용하는 셈이라는 것에 비해, C++은
call by value가 기본이기 때문에 Fortran처럼 사용하기 위해서는
함수에서 pointer를 사용해야 한다는 것이다.

포인터는 기본적으로 변수의 주소를 가리키는 것이라고는 알고 있지만,
가장 헷갈리는 것은 * 와 & 의 사용법과 함수에서의 input/output으로의 사용법이다.
문제를 더 복잡하게 만드는 것은 C/C++ 에서는 array와 C-string 을 pointer로
취급한다는 사실과 reference의 경우에는 implicit referencing과 dereference가
자동으로 일어난다는 점, 그리고 * 와 &가 문맥에 따라 다른 의미로 사용된다는
점이다. 이 때문에 포트란이나 파이쏜에 익숙한 내가 보기에는 일관되지 않은 사용법이
나타난다.

내가 이해하는 범위에서 포인터,레퍼런스 등의 사용법을 살펴보도록 하자.

(1) a, *a, &a 의 차이가 무엇일까?

일반적인 변수는 'int a' 와 같은 형태로 선언한다. 이 때, 컴파일러는 이 변수마다 주소를 할당하고 프로그램에서는 이 주소에 값을 저장한다. ( 집이 변수, 집 안의 물건이 변수값, 집의 주소 의 관계로 생각할 수 있다.) b=a 와 같은 명령은 집 a안의 물건을 집 b 에 복사하는 역할을 한다.

포인터는 'int* a_ptr' 과 같이 선언한다. 이 때, 'a_ptr'은 포인터로써 주소값을 가진다.
'*' 는 포인터(주소)가 가리키는 집안의 물건을 꺼내는 역할을 한다. (즉, '*' 는 포인터를 물건으로 바꾸는 역할을 한다.)

한편, '&'는 변수의 주소를 나타낸다. ' &a' 는 a 라는 변수의 주소를 준다.
(즉, '&'는 물건을 주소로 바꾸는 역할을 한다.)

int thing; // thing은 일반 변수(집) 이다.
int* thing_ptr ;// thing_ptr은 포인터(주소)로 선언한다.

thing  : 변수(집)
          thing = 4; // thing 에 숫자 4를 넣는다.

&thing : 변수 thing의 주소

thing_ptr : 포인터(주소)
          thing_ptr = &thing ;
          // &thing은 thing의 주소값이고,
           thing_ptr은 따라서 thing의 포인터가 된다.
           따라서 이후로는 thing과 *thing_ptr은 같은 것을 나타낸다.

*thing_ptr : 어떤 것(이 경우는 정수).
           other = *thing_ptr;
           // *thing_ptr은 thing_ptr 주소가 나타내는 변수(집)이므로,
           other라는 집에 thing_ptr이 가리키는 것을 넣는다.
           여기서, other는 정수값이 된다.

            *thing_ptr = 5; (?)
            // *thing_ptr은 thing_ptr 주소가 나타내는 변수(집)이므로,
                       thing 에 5라는 숫자를 넣는 역할을 한다. (?)

*thing :  thing은 포인터가 아니므로 틀린 문법.

&thing_ptr : 포인터의 포인터.

좀 더 정확한 pointer와 reference의 차이는 앞의 글 참조.

(주의?) c++의 character pointer 는 다른 포인터와 달리 string의 pointer 로 취급한다?

char some_characters[10] = "Hello";   // A simple set of characters
char *char_ptr = &some_characters[0];  // Pointer to a character
std::cout << some_characters << "\n" // output is "Hello"
std::cout << &some_characters << "\n"l //output is an address
std::cout << some_characters[0] << "\n"l //output is "H"
std::cout << &some_characters[0] << "\n"l //output is "Hello"
std::cout << char_ptr << '\n'; // output is "Hello"
                // So with string pointers, the string itself is printed.
std::cout << *char_ptr << "\n";      // output is "H"
std::cout << &char_ptr << "\n";  // output is an address

In a similar way, one can define string pointer directly,
```c++

char *test_ptr = "abcde"; // equivalent two step   
std::cout << "String pointer test= " << test_ptr << "\n"; //output is "abcde"
std::cout << " *test= " << *test_ptr << "\n";             //output is "a"      
std::cout << " &test= " << &test_ptr << "\n";             //output is an address  
```

(주의) c++의 pointer 와 array는 같이 방식으로 취급된다. 

char array[10] = "012345678";
char *array_ptr = &array[0];

array_ptr=&array[0];
array_ptr= array ; // these two lines are quivalent. 

When passing an array to a procedure, C++ will 
automatically change the array into a pointer

한편, string이 아닌 숫자의 array의 경우는

int array[10] // initialized as 0,1,2,3,4,5,6,7,8,9

std::cout << " array= " << array << "\n"; // output is an address
std::cout << "&array= " << &array << "\n"; //output is an address same as above
std::cout << "*array= " << *array << "\n"; //output is 0
std::cout << " array[1]= " << array[1] << "\n"; //output is 1
std::cout << "*array[0]= " << *array[0] << "\n"; // error ! this setence is wrong
std::cout << "&array[1]= " << &array[1] << "\n"; // output is an address

즉, array 는 array[0]의 위치를 가리키는 pointer 이다. (array와 &array[0]는 동일)

반면, array[0]나 array[1] 은 integer 이고, pointer가 아님. 

함수가 다음과 같이 정의 되었을 때
void init_array_1(int data[])
void init_array_2(int *data_ptr)

다음 둘은 같은 역할을 한다. 
init_array_1(array);
init_array_1(&array[0]);
그리고 
init_array_2(array)
도 비슷하게 사용가능하다.  





2017년 11월 20일 월요일

(퍼옴) Pass by value and Pass by reference

Here is  a link to the original page:

https://stackoverflow.com/questions/373419/whats-the-difference-between-passing-by-reference-vs-passing-by-value

Though the author writes that the analogy is not exact, it feels like the old explanation is
more natural and easy.
In short,

Analogy: Transferring a webpage,

Pass by reference: give the URL of webpage and authority to change.
Pass by value: give the printout of webpage

By default Fortran uses 'pass by reference' and C++ uses 'pass by value'.

In Fortran, subroutine calls f(x,y) and do something to the x and y then
it makes difference. In Fortran, one uses INTENT to avoid accidental change of contents.

In C++, since the default is 'pass by value', it does not change the original variable.
However, it would be inefficient to pass all big object by value. So, sometimes passing
a reference by using ' & var' is more convenient.

Difference between '&' and '*' in C++:

They are similar in the sense that they refers something in the memory.

Here is an original explanation:
https://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1047588532&id=1043284376

https://stackoverflow.com/questions/28778625/whats-the-difference-between-and-in-c

In short, '&' is used for objects reference but '*' is for a pointer of address.
( ** is used for a pointer of a pointer. For example, "char** argv" or "char* argv[]"
argv is an array of characters. Each char* is a pointer of a first character in string.
Then, char** is a double pointer for a pointer of a pointer to a character. )


* and & as type modifiers

  • int i declares an int.
  • int* p declares a pointer to an int.
  • int& r = i declares a reference to an int, and initializes it to reference i.
    C++ only. Note that references must be assigned at initialization, therefore int& r; is not possible.
Similarly:
  • void foo(int i) declares a function taking an int (by value, i.e. as a copy).
  • void foo(int* p) declares a function taking a pointer to an int.
  • void foo(int& r) declares a function taking an int by reference. (Again, C++ only)

* and & as operators

  • foo(i) calls foo(int i). The parameter is passed as a copy.
  • foo(*p) dereferences the int pointer p and calls foo(int i) with the int pointed to by p.
  • foo(&i) takes the address of the int i and calls foo(int* i) with that address.

설명: 비록 C++ compiler 는 (int* p) and  (int *p) 를 구분하지 않지만,의미는 다르다.
(1) (int* p) 는 p 라는 포인터를 선언하는데, 그 포인터가 가리키는 것이 정수라는 의미이다. 
    foo(int* p) 라고 정의하면, 함수 foo는 포인터를 변수로 받는데, 그 포인터는 정수 변수를 가리킨다는 것이다. 때문데 foo를 사용할 때는 foo( &i) 와 같이 사용하거나, foo(p) 로 pointer를 주어야한다.
(2) 반면, foo(int& r) 로 선언하는 경우는 foo가 변수 r을 받되 call by reference로 받는다는 의미이다. 때문에 사용할 때는 foo(i) 로 사용한다. ( foo(p)나 foo(&r) 은 옳지않다.)


(tl;dr) So in conclusion, depending on the context:

2017년 8월 21일 월요일

How to import existing fortran code into python

Since there are many existing fortran codes, it would be better to use them
in python. One possible way to do it is to create a shared object(.so) file by using f2py. 
Simple example of using f2py can be found easily. 
But, in case of complicate fortran program which use 'make',  or in case of the subroutine we want to use is a part of larger library, it is not clear how to 
achieve it. 

The steps are 
(1) Prepare a module code which includes all the subroutines which wants to be 
    ported to python. 
    It is recommended the subroutines includes both input and outputs explicitly 
    by 'intent(in)' and 'intent(out)' properties. 

(2) create a static library for the subroutine (first compile for object files)     
     ar crsv lib[name].a [object files]

(3) use f2py to create signature file (.pyf) . 
    f2py [source file] -m [package name] -h [signature file name]

    Here the [source file] contains the subroutines or its wrapper to be imported to python. signature file (.pyf) contains a module for python which contains subroutines.
Importing sub module does not work well. Thus, always prepare [source file]
as a wrapper with subroutines not modules.

(4) edit the signature fil( .pyf) as necessary. (Only leave the subroutines to be imported) 

(5) created shared object library(.so) file using f2py 
    (If path of library is the same, "-L." would work?) 
    f2py -c [signature file .pyf] [source file] -L[absolute path for library]-l[library name] -llapack

(6) In the python,
    import [package name]

     and now one can use subroutines,
    [packagename].[subroutine]

(7) in case that the library(.so) file is located in different folder,
    add the library path before import

    import sys
    sys.path.insert(0,'[Library Path]')



  • The simple case: If there is only one fortran file, one can do 
  • (1) edit/comment the fortran file "my_lib.f90" with "!f2py " comments or explicit "intent" expressions.
  • (2)  Use following command to create  " my_lib.so " file which can be imported in python by "import my_lib" , 

f2py -c -m my_lib my_lib.f90

# Another way to use f2py is 
   directly add "cf2py intent([in/out]) [variable]" in the fortran source code 
   and compile 
   "python -m numpy.f2py -c -m [module name] [fortran source]" 

# In Windows, there seems to be some issue with the version of mingw-w64. 
  It seems I have to use "x86_64" version of mingw-w64 instead of "i686" version. 
  More details on the installation. 
  (https://python-at-risoe.pages.windenergy.dtu.dk/compiling-on-windows/configuration.html) 

# In Windows, one can use "ar" to create library as like LINUX with mingw-w64.

# Currently(2025.02.25), there seems to be a problem using f2py and "meson" build system in Windows... I am not sure how to fix the error. The same code can be compiled in linux.  









python library path 설정

Note that the python path is not the same as the system $PATH.

(1) To list the python path,
     import sys
     print(sys.path)

(2) To insert a path,
    sys.path.insert(0, '{PATH TO INSERT}')

    This enables one to import library from other folder.

2017년 5월 16일 화요일

Tikz-Feynman package for Feynman diagram

There have been several packages to draw Feynman diagrams in tex environment.
But I have used two:

Axodraw ( Jaxodraw)
Feynmf (Feynmp)

However, one is rather old and non-standard and the other is not easy to use.

New package "Tikz-Feynman" seems to be good in look and easy in usage.
However, when I try to use the package the diagrams are weird and different shapes
from examples.
The problem was that I compiled them with 'pdflatex'.
It looks like the "Tikz-Feynman" is only compatible with 'lualatex'.
Since it is not written in the manual or webpage, it was difficult to know.

On the other hand, I found each package have advantage and disadvantage.
It is mostly how the vertices are positioned by the command.
For me, Feynmf seems to be better than others. But, because it use metafont,
it is rather slow and I have problem with TexStudio using Feynmf.
(I had to delete metafont whenever I modify them).

2017년 4월 13일 목요일

Shell model code NUSHELL tips

1. In old version of NUSHELL, be careful for the 'psd' model space.
   The single particle levels defined in the 'psd.sp' and interactions like 'psdmk.int'
   may be not consistent.
   The level ordering in original 'psd.sp' file is

   1 1 1 3  (p3/2)
   2 1 1 1  (p1/2)

   But, it have to be changed as follows to be consistent with the definitions in 'psdmk.int' interaction file.

   1 1 1 1  (p1/2)
   2 1 1 3  (p3/2)


---UNDER CONSTRUCTION

2017년 3월 29일 수요일

Python referencing( copying variables, objects)

In many language (at least, in Fortran), '=' makes a copy of a variable, so

a=1; b=a;  b=2

makes a=1 and b=2. Thus any change of the copy does not change the original.
This is the same for python, if the variable is a simple object.

However, in python, 'list1= list2' does not make two lists. Instead it refers the same reference object. Since, if a new value is assigned to the list, it may be okay.

a=[1,2,3]; b=a; b=[4,5,6]

makes a as [1,2,3] and b as [4,5,6] since the last  assignment 'b=[4,5,6]'
can be considered as a new assignment.

However, if we modify its elements,

a=[1,2,3]; b=a ; b[1]=7

makes both a and b as [1,7,3] (instead of a as [1,2,3], b as [1,7,3] )
since a and b were both refer the same object.

To obtain the originally desired effect, one can use

(1) b=a[:]  or b[:]=a[:]
(2) b=list(a)
(3) b=copy.copy(a)