Welcome to My webpage
亦欲以究天人之际,通古今之变,成一家之言。 ——司马迁
我叫杨春雨,来自江苏泗洪,中国科学技术大学化学物理系本科三年级在读,现在在侯中怀老师课题组做一点复杂体系的动力学理论研究以及分子动力学模拟。这是我的第一篇博客。
我将在这里分享自己的学习、探索的历程,以及对一些问题的思考。如果你想要联系我,我的邮箱是:chyyangustc@mail.ustc.edu.cn和larkyoung@foxmail.com。
亦欲以究天人之际,通古今之变,成一家之言。 ——司马迁
我叫杨春雨,来自江苏泗洪,中国科学技术大学化学物理系本科三年级在读,现在在侯中怀老师课题组做一点复杂体系的动力学理论研究以及分子动力学模拟。这是我的第一篇博客。
我将在这里分享自己的学习、探索的历程,以及对一些问题的思考。如果你想要联系我,我的邮箱是:chyyangustc@mail.ustc.edu.cn和larkyoung@foxmail.com。
我们先从一个最简单的Fortran程序看起
1 | program HelloWorld |
当我们使用Fortran语言的时候,主程序要写在program
和end program
之间,且program
之后需要跟程序的名称,这个名称不必和文件名相同。
Fortran使用!
标志注释行。implicit none
的作用是要求程序不使用隐式变量声明(不然的话i,j,k,l
这些会默认为整数类型)。
在上述程序中,我们使用了write
函数,这个函数接受两个参数。一个是输出的开始位置,默认为6(非默认情形我们稍后讨论),另外一个是格式化参数。Fortran中的输出函数还有print
,它只接受一个参数,即格式化参数,换而言之,他只能输出到屏幕上。
read
函数有两种写法read(*,*)
和read *,
,分别类似于write
和print
。
输出的格式化按照如下的方式进行,输入同理。
Iw[.m]
以w个字符的宽度来输出整数,至少输出m个数字。Fw.d
以w个字符文本框来输出浮点数,小数部分占d个字符宽,输出文本框的设置不足显示*号。输出不足补空格,小数不足补0。Ew.d[Ee]
用科学计数法,以w个字符宽来输出浮点数,小数部分占d个字符宽,指数部分最少输出e个数字。
!输出不足部分补空格,小数部分不足补0。Aw
以w个字符宽来输出字符串。nX
输出位置向右移动n位。Fortran中的数据类型有整型(integer)、实型(real)、复数型(complex)、逻辑型(logical)、字符型(character)等。
整数和实数类型的使用方式类似C语言,但是可以通过(kind=n)
的形式来指定精度,当然括号中的是可选部分。
1 | integer(kind=4) :: int_num |
Fortran是少有的原生支持复数类型的语言,复数以类似向量的方式来表示,
1 | complex :: a,b |
此外还有字符串类型和逻辑类型,如果字符串类型没有初值,则必须指定长度,
1 | character str_1='abcd' |
如果接下来赋给str_2
的值的长度大于10,则会自动截断到10。
逻辑判断类型无需多说,其使用方式为
1 | logical a,b |
Fortran中的数组定义有两种方式
1 | integer :: student(5) !一维数组 |
值得注意的是,Fortran中的数组索引从1开始,而且按列索引。
以下是一些数组的操作的例子
1 | integer :: a(3,3),b(3,3),c(3,3),d(5),e(5),f |
Fortran中可以声明可变大小的数组,只要在声明的时候加上allocatable的形容词,并注明是数组的维度,在后续需要确定大小的时候为数组配置内存空间即可。
1 | program allocatable_array |
Fortran中的if
语句和C语言是类似的(其实多数程序设计语言在这里都是类似的,而且说Fortran类似C本身并不合适,因为Fortran是最古老的程序设计语言,如果某个语言与之相似,则应该该语言借鉴了Fortran,不过按照现在的现在普遍规律,多数人都应该先学C语言再学的Fortran,为了便于大家理解Fortran所以说Fortran类似C)。
1 | if (logical expression) then |
当然还有if... (else if..). else ...
的结构
1 | if (logical expression 1) then |
我们可以给if
语句一个名字
1 | name if (logical expression 1) then |
当然不止if
语句有这样的功能,Fortran中的所有块都可以给一个名字。
select case
类似于C语言中的switch case
,但是功能上更加灵活,支持简单的比较判断,支持整数,字符类型。
1 | program selectCaseProg |
Fortran中的do
循环类似于C语言中的for
循环,其基本格式为
1 | do var = start, stop [,step] |
var
需要是一个整数,step
的默认值是1。
do while
循环类似于C语言中的while
循环。
1 | do while (logical expr) |
exit
语句终止循环或select case
语句,并将执行立即循环或select
下面的语句。这个时候,给循环赋一个名字就很有用,当循环是嵌套的时候,可以直接指定退出某一层循环
1 | program nestedLoop |
这个类似于C语言中的continue
,将会跳过循环的剩余部分,开始下一段循环。
stop
语句的作用是停止程序的执行,后面可以跟着字符串和数字,表示返回值。
Fortran中自定义代码片段两种:子程序subroutine
和自定义函数function
,他们的不同之处在于返回值和传参方式
子程序的一般结构为
1 | subroutine name(arg1, arg2, ....) |
它没有返回值,但是子程序可以修改传入的参数的值。
自定义函数的一般格式为
1 | function add(a,b) |
自定义函数有返回值,且传入的只是变量值,自定义函数外的变量不会受到影响。
Fortran的文件操作比C语言要简单很多,主要依赖于open
,close
,read
,write
四个函数。
在对某一个文件进行处理之前,需要打开该文件,最简单的方法是
1 | open (unit = number, file = "name") |
接下来对该文件进行读写只要使用write
和read
函数就可以
1 | write(number,*) "string" , num |
当这个文件不再被使用的时候,应该使用close
关闭
1 | close(unit=number) |
这部分显然不需要说太多,下载vscode
应该是一件非常容易的事情,只需要进入vscode的官网,下载.exe
(Windows),或者.zip
(Mac
OS)文件,点击安装即可
我本人推荐使用的TeX
发行版是TeX Live
,所以这里也就只介绍TeX Live
的安装。推荐使用清华大学的镜像,点击进入,下载texlive.iso
文件即可,这个不带日期的版本默认是最新的。
下载之后打开.iso
文件,点击install-tl-windows.bat
安装即可。
安装过程大约需要2个小时。耐心等待即可。
很多同学习惯于用中文作为用户名,但是这样会导致 TeX Live
安装失败。更改 系统的 TEMP 和 TMP
这两个环境变量可以避免这样的问题。在命令行中运行
1 | mkdir C:\temp |
然后再点击安装即可。这样修改环境变量是暂时的,等到cmd
窗口关闭,环境变量会自动恢复原样。
MaxTeX
是TeX Live
的一个为 Mac OS
所定制的发行版,所以对于使用 Mac OS的推荐使用
MacTeX
。同样我们也可以到清华镜像站下载。对于
Mac OS 用户,Homebrew 是一个非常方便的包管理程序,如果你安装了
homebrew,可以通过下面的方法安装 MacTeX
1 | brew install MacTeX |
在已经完成了上述工作的基础之上,接下来就可以进行vscode的配置,不过和配置C语言环境相比,配置vscode要简单得多,安装插件LaTeX Workshop
。然后进入设置,在文本模式中编辑设置,把以下代码复制进去:
1 | "latex-workshop.latex.tools": [ |
部分命令已经带有了注释,可以自行修改。如果有同学想要进一步了解这些命令,可以自行查看LaTeX Workshop
的文档,这里不赘述。此外还可以设置使用外部阅读器查看PDF,可以自行使用搜索引擎完成。
完成上述设置之后,就可以使用vscode编辑LaTeX了。
snippet就是自定义的代码补全,在vscode
中ctrl+shift+p
,搜索snippet,选择配置用户代码片段,在弹出的文本中输入即可。同时还需要再刚才的setting.json
中输入"editor.snippetSuggestions": "top",
。
有一个网站可以自动将命令转化为snippet。读者可以自行去了解,使用snippet确实是一种非常好的提供效率的方式
As we have noted before, Mathematica is similar to Lisp. So let us talk about some characters of Lisp before we discuss the Mathematica.
Actually, Lisp is the abbreviation for list processing. List is an object take the form of:
1 | (item1,item2,item3) |
The list is also named as symbolic expression. The target of the
interpreter of Lisp is to get the value of each symbol expression passed
to it. The compiler takes item1
as the name of the function
and item2
and item3
as variables. The method
was invented by Jan Łukasiewicz from Poland, so it is named as Polish
notation. Despite its difficulties for human to understand, it is
convenient for the computer to cope with. When we compile a program, we
need to convert the source code to abstract syntax tree. So the way we
write Lisp is just writing a syntax tree.
In Mathematica, the function Treeform
can get a
expression's syntax tree.
1 | TreeForm[(a + b^n)/z == x] |
Have a try, and some surprises are waiting for you. If we want to write the expression above in Lisp, then it would take the form of
1 | (==,(*,(+,a,(expt,b,n)),(expt,z,-1)),x) |
Actually, the kernel of Mathematica understand the expression in the same way.
1 | In:FullForm[(a + b^n)/z == x] |
The the similarity is very conspicuous.
==Everything is An Expression== is a philosophy that both Mathematica and Lisp follow (actually, it is more proper to say Mathematica get the idea from Lisp). Now let's review the definition of expression:
Then we go on to illustrate why we say everything is an expression.
1 | In: Map[FullForm,{a+b,a-b,a*b,a/b,a^b,a==b,a!=b,a<b,a<=b,a>b,a>=b,a&&b,a||b} ] |
Though, expressions like a+b
,a-b
and
a!=b
is not take the form of Map[f,expr]
is equivalent to f\@ expr
.
We could find that the first principle only care about the method we use to denote the object to be computed. It doesn't take the computation itself into consideration. ==Lisp is not good at computation==, and that's why Wolfram unsatisfied with Lisp. Mathematica got its way of computation from other functional programming languages like Haskell and OCaml.
In order to understand that, let's recall how we human perform
computation. Just take a integrate as an example,
There is no rewriting system in Lisp, and Haskell and OCaml don't take everything as list, but we still classify them into one category which is so-called functional language. Why we do that?
In Lisp, we could add a '
to prevent a list get its'
value, and the we take the list as some kind of data which is
manipulative. When we combine some data to a List, we could use
(eval L)
to force the list get its value. Then the data L
be converted to executable code again. We call Code-as-Data as the
philosophy of Lisp.
In Haskell, we take every category as a set. Functions between
categories are just the map between sets. It's easy to combine .
.
What's more, all the map from
The character is so important that we call it Mathematica's zeroth principle: Function Matters, not variables.
A expression is defined as an atom or a function like
Given a expression
1 | In:Head /@ {1,1/2,True,"Number",a+b,a-b,a*b,a/b,(f+g)[x1,x2,x3]} |
Note:f\@expr
is Map[f,expr]
We could find that for atom, a symbol's head is always
Symbol
, a number's head depends on its type and could be
Integer
, Rational
, Real
,
Complex
, a string's head is always String
,
etc. We could decide whether a expression is an atom in this manner.
1 | myAtomQ = |
However, sometimes we need to deal with the parameters of a
expression. Then we take them out, but what we get turns out to be only
a sequence compose of several expressions, and there is no head with
them. But all of expressions of Mathematica must have a head. In order
to deal with a expression without head, Mathematica introduce list and
all of expressions don't have a head have a head of List. The case
bellow shows that when we apply List
to a expression, it
become a list
.
1 | In: ex = f[x1, x2, x3]; |
List itself is also an inner function of Mathematica, and it could turn a sequence of expressions into as list. eg
1 | In:List[1,2,3] |
@@
, whose full name Apply
, is also a
functional operation and it change a expression's head. eg
1 | In:Apply[g,h[x1,x2,x3]] |
There is also another type of list which is so-called
Sequence
. We could take sequence as a list without
{}
in both sides. Or we could say, list is turn a sequence
into an object while sequence is something more basic.
1 | In: ex = h[1, 2, 3] |
And when we want to convey the parameters of one expression to
another expression, we can't get what we want because of the
{}
. Therefore we need to change the head of that expression
to Sequence
.
1 | In: f[seq] |
Apart from Head
and Apply
, we could use
the built-in function Part
to visit expression inside
compound expressions. It takes the form of
Part[expr,number]
or expr[[number]]
and 0 is
the head.
1 | In: ex = f[x1, x2, x3]; |
As we have discussed before, the type checking of Mathematica is not
so strict and as a result of there is no ex[[4]]
,
Mathematica return us a result of f[x1, x2, x3][[4]]
. It's
often the case that when Mathematica doesn't know what to do with our
command, it would return what it get to us.
And for nested expressions, we can take Part
more than
one time.
1 | In: ex = f[a, g[b, c], h[d, k[e, i], j]]; |
The operation could also write as ex[[3, 2, 2]]
. There
are many other ways to use Part
, and we show this by four
examples
1 | In: ex[[-1, -2, -1]] |
There are also some built-in functions for some Parts which are often used.
1 | In: Function[op, op[f[x1, x2, x3, x4]]] /@ {First, Last, Rest, Most} |
For a given expression, there are two values matter. i.e. depth and length.
1 | In: Length[f[g[x1, h[x2, x3]], x4]] |
Like many other language, Range could be used to build a simple list.
1 | Range[begin,end,step] |
Only end
is a must to this function. And
Table
, Array
, Turples
and
Outer
can be used to build a list too.
1 | In: Table[i^2 + i + 1, {i, 10}] |
Tuples[List,n]
means use members of the list to
construct lists of n numbers and combine all possible answer to one
list.
1 | In: Tuples[Range[3], 3] |
Outer[f,list1,list2]
group all the possible combinations
of members of list1
and list2
and use them as
the independent variables of f
.
1 | In: Outer[f, Range[3], Range[2]] |
MemberQ[expr,i]
is used to judge whether i
is a member of expr
, while FreeQ[expr,i]
is
used to judge whether expr
has a sub-expression which
matches i
. Both of them will return False
,
when i
is the head of the expr
.
1 | In: ex = f[x1, x2, x3, x4]; |
And we could appoint the depth of searching for them.
Count[expr,i]
is used to calculate how many times
i
appear in expr
, appoint depth is also
powered.
1 | In: euler = (a + b^n)/n == x; |
Use n
means searching from 0th layer to nth layer, while
use {n}
means only search nth layer.
1 | In: Position[euler, n] |
And we could use Select
to choose members by
self-defined rules.
1 | In: Select[Prime /@ Range[10], OddQ] |
This is a note to the course "Core Language of Mathematica" given by Siqi Liu in Bilibili. There is also a PDF version in Chinese.
Firstly, we talk about why we use Mathmatica. The question is quite open and people in different areas will give different answers. So we begin with the way of a scientific worker workes:
So, scientific workers would use plenty of simulation and experiments. In order to enhance the efficiency of work, we get the machine to share some of our work. Specifically, for people who need computation, we should get the computer to help us. So we need programming.
And then we need to choose the most efficient way of programming. The efficiency of programming is decided by the time we spend writing and using it. In most cases, the time of running a program for once is far shorter than the time we need to write it. And usually, we scientists would run the program only once. As a result, the most efficient way is just the fastest way to write a program.
The language of Mathematica is close to natural language and it has many built-in functions and well developed documents, which makes it very suitable and easy to write a program, thus shortening the time we need to develop a program.
We could learn about the history of Mathematica in the web site Mathematica—Three Decades of Contributions, Invention, Discovery, and Education (wolfram.com), and as Mathematica is developed by C, it is similar to C in some respects. When Wolfram developed the Mathematica, he got many inspirations from Lisp which lead to the similarity between them.
The calculation in Mathematica will always be performed in high precision and it could function as a calculator itself. Like:
1 | In: 1+1 |
But its capacity is far more than the arithmetic operation and call
simple functions. We could use Expand
to perform expansion,
Factor
to perform factorization, Solve
to
solve equations. Some functions of advanced mathematics are also
equipped, like Dsolve
to solve differential equations,
D
to perform derivation, Limit
to get the
limit of a function, Sum
to calculate the series.
When you are performing a series of computations, if you worry about the contamination of variables, you could reopen the kernel.
Apart from the simple functions we have noted above, Mathematica has
a lot of advanced built-in functions. For example, we could use
Import
to get data from the internet. And we could also
deal with pictures and music with Mathematica, capture stock data from
the Internet to achieve quantitative trading.
In Mathematica both the functions and constants use the Upper Camel
Case. As a result, to avoid using the reserved words, we could use the
Lower Camel Case. The comments are written in the form of
(* comments *)
. If an element has got an value, it would be
black and if not it would be blue.
The notes is from the course "Core Language of Mathematica" taught by Siqi Liu, Tsinghua University. And as the document of Mathematica is so strong, we don't talk about the details of many functions unless we need to do that. We mention the usage of the function and readers could just read the details of the function in the document of Mathematica.
We highly recommend our readers to use genuine software. The price is not so unaffordable. If you think it is quiet costive, there are still a way to use the Mathematica legally. In May 2019, Wolfram put forward Wolfram Engine, and it is free of charge. And there many ways to add a notebook to the kernel. I recommend this passage 在 VS Code 中使用 Wolfram 笔记本 - 知乎 (zhihu.com).
In Mathematica, there are two fundamental principles. Firstly, everything is a expression. Secondly, computation is just rewriting.
In Mathematica, numbers, strings and symbols are called atom. An atom
is a expression and if
And when we perform computation in Mathematica, what we do is just get a repeatable regime in what we need to compute and interpret it to Mathematica. Thus, rather than variables, what we actually care about is the functions. i.e. Mathematica's zeroth principle: functions matter, not variables.
In this section, we will talk about the basic grammar of writing a Mathematica programm.
The type checking for Mathematica is not strict, for example:
1 | In: Sin["I'm a String!"] |
The less stricter the type checking, the more flexible the programming. Of course, it may incur errors. But usually a Mathematica program is short, so developers could check the error by themselves.
We will see some skills base on the loose type checking of Mathematica in later sections.
The If
of Mathematica take the form of
If[conditional judgement,True's opertaions, Else's operations, Unevaluated' operations]
.
For example:
1 | If[a==b,Print["Then"],Print["Else"],Print["Unevaluated"]] |
In Mathematica, ==
means equal while ===
means sames.
比较合适的时间是每年的一月份,刚好考完期末,时间比较充裕,而且这个时候教授们也都处理完了或者快处理完了去年的招生事宜。最好在一到二月份解决,再往后签证的时间可能比较紧迫,也可能你想找的教授以及招到了不少学生了。
也不推荐太早,如果你头年10月就找到了暑研,你会发现接下来的八九个月如何和教授保持联系还是一件蛮头疼的事情。
暑研申请没有什么成本,而且是自费(USTC
Fellowship)所以大胆申请就好,突出一个人有多大胆,地有多大产。
直接去六大、Yale、JHU等学校主页扒它们的老师就好,我自己看的时候会习惯了解一下这个老师组里面是否有亚裔。不过绝大多数教授组里面都是有的。
除此以外,可以问一问组里面的博士师兄,或者直接问自己的老板,如果老板有一个不错的connection能够直接把你扔出去那就再好不过了。就算不能,他们对做的比较好的组和他们是否喜欢中国学生也是有一些了解的。也可以问一问学长学姐(我也可以,欢迎联系chyyangustc@mail.ustc.edu.cn)。和学长学姐交流能够少走不少弯路,出国如果是自己diy,一定不要闭门造车。
遇到感兴趣的直接发邮件,可以认真了解他的研究之后再好好写一份邮件、也可以大概了解之后按照模板发(半海套)。
不过大多数时候可能你花了好长时间读懂了他的几篇文章,然后结合自己的经历写了很长的文章,然后在人家的spam里面,或者人家看到了,但是不回复,这种情况还是蛮打击人的。而且多数情况下,想招的自然会招,不想招的也不会因为你很优秀就招你,所以我觉得最好的方式还是半海套。
当然,暑研的回复率低实在是太正常了,因此如果连发三四封邮件没人回复先别气馁。
在看教授课题组主页的时候(如果有的话),可以关注一下有没有USTC的学长、学姐,可能会有USTC的学长学姐在他们那边读博、做博后。这种情况可以联系一下,万一能说上一句话呢。一定要善用校友资源,我们年级有两位同学通过科大老学长申请到了Harvard的暑研。
除此以外,如果教授给你回复了,但是拒绝了你,给出了理由是要去旅游之类的。当然不排除完全是礼貌性的拒绝理由,但是最好还是给一个礼貌的回复。比如:I am really interested in your research and hope to get admitted into your group when I apply for the PhD. 万一明年真的申请他了,有个脸缘总是好事情。
我自己想要申请的方向主要是分子模拟,当然电子结构计算也可以接受。最后申请的是芝加哥大学的Greg Voth,不过芝大的暑研确实蛮麻烦的,一方面要收学费($1400),另外一方面流程上比较繁琐要推荐信、要托福。而且如果你不是按照他们的学期取得,你的学费就double了,夏季学期从6.12到9.25,秋季是9.26到12.6,总的来说时间的契合度有点低。可以优先考虑其他学校(如果能够套到的话)。
此外,如果想做电子结构计算的话,UWM的Yang Yang是一个很好的选择,人非常的nice。我原本以为Voth不会回复我了,就联系了他,他非常热情。但是就在发邮件给他的第二天,Voth回复了我,考虑到Voth的工作和我的方向和兴趣都更加契合一些,我最后还是选择了Voth,感觉很对不起他的热情。发邮件给他解释了之后,他给我回复了:“No worries at all. Good luck with your summer intern”。人确实非常nice,非常推荐做电子结构计算的同学考虑一下。
再说说避雷,主要避雷西北大学的Todd,他已经鸽掉了我们组的两位同学了。邮件联系之后要面试,面试先拖一个月,面试结束过了二十天告诉你他不想要你。从各种意义上说都有点不太合适。
所以陶瓷的过程中一定注意这样的老师养鱼(我猜是在养🐟,也可能只是拖沓),毕竟陶瓷最好的窗口期就一两个月,在一个老师身上花了两个月就结束了。因此尽可能选做事比较干脆的老师。
托福最好早点考,最好在大二下学期和大三上的时候能够有一份90+的成绩单,因为暑研申请的时候可能有一些学校会需要。
科大的量子化学课程主要讲授群论在结构化学领域的应用。从较为基本的分子对称性判断、分子点群的划归到分子点群的特征标表以及其在分子结构上的应用。
这门课程本身可能略有抽象,但是并不困难。不过科大化院很多课程最大的问题似乎都是,没有一个合适的教材或者参考书。因此,我在这里将我在2022年春学期的笔记上传,希望稍微能有一点用处。