阅读Fortran中的化学符号

时间:2017-07-20 20:58:26

标签: fortran chemistry

我正在阅读化学符号列表。由于有118个元素,select case构造将有119个案例。有一个更好的方法吗?有些元素以相同的字母开头,例如CCaCdCo,因此可能会读取三个A1个变量而不是一个{{1}变量可以稍微缓解这个过程。

A3

2 个答案:

答案 0 :(得分:2)

有一小组有限的元素符号(我相信最后一次计数为118),它可以放在一个不太长的文本字符串中。 Fortran不是文本处理的最佳语言(我会让Perl和SNOBOL争论......)但现代Fortran已经改善了一些事项。

以下代码中有一些假设。首先,我们希望用户在使用混合大小写时键入元素符号。您可以更正大小写但是对于此示例,如果用户输入中的第一个字符不是大写字母而第二个字符不是空格或小写,我决定只抛出错误。这是使用添加到Fortran 95中的语言的verify内在函数完成的(这是我第一次使用它时)。

index()内在函数将为您提供从1开始的较大字符串内的子字符串的第一个匹配的起始位置,或者如果未找到匹配则返回0。

elblob字符串包含由下划线分隔的每个元素符号。单个字母元素保留尾随空格以匹配character(len=2)变量。两个星号卡在elblob的前面,这样每个元素都从一个可被3整除的字符开始。这是一个愚蠢的魔法,它充分利用了我们对原子序数的了解 - 它们是独特的,连续的,整数,完全填充从1到118的范围(或者这些天最重要的元素)。

可能解决非问题的另一个偷偷摸摸的问题是使用adjustl()来确保elseek中的第一个字符不是空格。它可能不仅仅是因为Fortran read()的工作方式,但我是偏执狂所以我把它放在那里。它最糟糕的是燃烧几个循环而不做任何事情。拿出来看看会发生什么。

通过完整性检查用户输入以防止杂散的'_'和'*',我们可以确保元素符号将正确匹配,并且我们可以通过除以{{返回的匹配位置来获得真实的原子序数1}}三。碳不会意外地匹配钙,因为碳的搜索字符串是'C',而不是'C',这是Fortran固定长度字符串的效果。如果将index()定义为elseek,我们可能会遇到问题,但是通过使用愚蠢的旧固定长度空格填充字符串,我们可以使用他们愚蠢的旧行为来为我们带来好处。

character(len=:), allocatable

无论如何,我测试了30秒。不要将它用于任何安全至关重要的事情。如果这是作业,至少阅读并理解代码并将其重写为您自己的代码,这样您就不会被Turnitin标记。

这不是最强大的解决方案,但它简短而且符合书面要求。它不需要哈希表或搜索树或任何比字符串更复杂的数据结构。在FORTRAN77下工作并不需要花费太多时间,但那种方式就是疯狂......

答案 1 :(得分:1)

一般来说,我喜欢SELECTED CASE,但这似乎更直接......

MODULE Element_Definintions
IMPLICIT NONE

PUBLIC

INTEGER, PARAMETER, PUBLIC :: Max_Elements = 118

TYPE Elements_Type
  character(len=3)   :: Name
  integer            :: i
  real               :: mass
END TYPE Elements_Type

TYPE(Elements_Type), DIMENSION(Max_Elements), PUBLIC :: Elements

CONTAINS

SUBROUTINE Init_Elements
IMPLICIT NONE

Element(1).Name = "H"
Element(1).Num  = 1
Element(1).Mass = 1.008

Element(2).Name = "He"
Element(2).Num  = 2
Element(2).Mass = 4.008

!...
Element(118).Name = ""

RETURN
END SUBROUTINE Init_Elements

END MODULE Element_Definintions

然后程序......

program case_test
USE Element_Definintions
implicit none
character(len=3) :: input
LOGICAL          :: Found = .FALSE.

CALL Init_Elements()

write(*,*) "Give me a symbol"

read(*,"(A3)") input

DO I = 1, Max_Elements
  IF(Input(1:LEN_TRIM(Input)) == Element(I).Name(1:LEN_TRIM(Element(I).Name)) THEN
    FOUND= .TRUE.
    EXIT
  ELSE
    CYCLE
  ENDIF
ENDDO

IF(Found) THEN
  write(*,*) 'atom mass of "',Element(I).Name,'" = ', mass
ELSE
  write(*,*) 'Unknown element "', input,'"'
ENDIF

END program case_test