Skip navigation.

Posts tagged with "programming"

有限元法边界条件的处理

,

边界上的节点通常有两种情况,

1. 一种边界上的节点可自由变形,此时节点上的载荷等于0,或者节点上作用某种外载荷,可以令该点的节点载荷等于规定的载荷Q。这种情况的处理是比较简单的。

2. 另一种边界上的节点,规定了节点位移的数值。这种情况下,有两种方法可以处理:
* 划0置1法
* 置大数法

划0置1法是精确的方法,置大数法则是近似的方法。下面分别介绍这两种方法

置大数法

假设v自由度的位移已知为b(b可以为0或者其他任意值)。

1. 将v自由度相应对角线上的刚度系数 k(v,v) 换成一个极大的数,例如可以换成 k(v,v)*1E8
k(v,v) ---> k(v,v) * 1E8

2. 将v自由度相应节点载荷 F(v) 换成 F(v) * 1E8 * b
F(v) ---> F(v) * 1E8 * b

3. 其余均保留不变,求出的
v =~ b

此方法的处理只需要修改两个数值即可,简单方便,虽然求得的是近似值,但一般仍然推荐使用

划0置1法

假设v自由度的位移已知为b(b可以为0或者其他任意值)。

位移为0
1. 只保留相应主对角线上的元素k(v,v),其所在行(v)列(v)上其他元素均改为0。
2. 在载荷向量中,令F(v)=0
此时,求出的v = 0是精确解

位移不为0
1. 只保留相应主对角线上的元素 k(v,v),其所在行(v)列(v)上其他元素均改为0。
2. 在载荷向量中,令
F(v) = k(v,v)*b
F(i) = F(i) - k(i,v)*b i != v
此时,求出的v = b是精确解

划0置1法处理上比置大数法要麻烦不少,虽然求得的是精确解,但是还是使用比较少吧?

参考:朱伯芳《有限单元法原理与应用》

另外,谢谢小勇提供的有限单元法讲义

Fortran与c/c++混合编程

, , ,

Fortran90语法

,

下面的这些用法您用过吗?

Where Arrays allow a more compact notation for conditional assignment

real, dimension(100,100) :: a, b
...
where(a>0.0)
b = a
elsewhere
b = 0.0
end where

Mask operations There are also many conditional tests and masked intrinsics


if (all(a==0.0)) write(*,*) 'a is zero'
if (any(a==0.0)) write(*,*) 'a has at least 1 zero element'
write(*,*) 'a has', count(a==1.0), ' elements equal to 1'
a = merge(0.000001, a, a==0.0)
b = sum(a, a>0.0)
c = product(a+1.0, a>=-1.0)

Assumed shape and automatic With array notation comes the possibility of assumed shape


subroutine foo(a,b)
real, dimension(:,:) :: a
real, dimension(0:,-5:) :: b
...
end subroutine foo
and automatic arrays

subroutine foo(a)
real, dimension(:,:) :: a
real, dimension(size(a,1), size(a,2)) :: b
...
end subroutine foo

Case Often want to test for more than one condition. An if-then-elseif-else-endif tree is not suitable. Fortran 90 provides a case statement

select case(ch)
case('a','c','d')
x = sin(y)
case('w':)
x = cos(y)
case default
x = y
end select

Intent Fortran90 provides a mechanism to tell the compiler about how variables are used within a sub program. This allows the compiler to provide additional checking and optimisation.


subroutine foo(a, b, c)
real, intent(in) :: a
real, intent(inout) :: b
integer, intent(out) :: c
...
end subroutine foo
now, something like a=1.0 inside foo will generate a compiler error. Also, c will be undefined on entry into foo

Optional arguments Subroutines and fuction can have optional arguments in Fortran90


function foo(a, b)
real :: foo
real, intent(in) :: a
integer, intent(in), optional :: b

if (present(b)) then
foo = a**b
else
foo = a
end if
end function foo

Interfaces F77 did not have type checking for arguments to subroutines and functions. F90 allows the declaration of an interface to a sub program which the compiler will then enforce.


program main
interface
real function fun(x)
real :: x
end function fun
end interface

real :: y

y = fun(10.0) ! Calling y=fun(1) will produce a compiler error.
end program main

Modules Modules provide a mechanism to package data types, derived types, function, subroutines and interfaces together. Including a module gains access to all public components within that module and automatically defines interfaces to all functions and subroutines within.


module foobar
real :: a
integer :: b
contains
subroutine foo(c, d)
integer :: c
real :: d

d = d * a**c + b
end subroutine foo
end module foobar

Using modules A module can then be used to gain access to its components


program main
use foobar

real :: x

x = 10.0
b = 3
call foo(5, x)
end program main
Since the subroutine foo is within a module its interface is automatic and enforced by the compiler.

Modules cascade Modules can be cascaded.


module aaa
...
end module aaa

module bbb
use module aaa
...
end module bbb

module ccc
use module bbb
...
end module ccc
Module ccc now has access to all public objects within module bbb and module aaa

Being more specific, You can elect to use only certain objects from a module


module bbb
use aaa, only: foo, bar
...
end module bbb
which only gains access to foo and bar within module aaa

Public and private You can state which objects within a module are publically available or private


module foobar

private
public :: foo

real :: a
real, public :: b

contains
subroutine foo(...)
...
end subroutine foo

subroutine bar(...)
...
end subroutine bar
end module foobar

Derived types Ofter more complex data types are required. Fortran90 allows this through derived types.


type particle
real, dimension(3) :: pos, vel, acc
real :: mass
integer :: n
end type particle

type(particle) :: p

p%mass = 1.0
p%n = 1
p%pos = (/ 1.0, 2.0, 4.0 /)
p%vel = 0.0
p%acc = 0.0

Derived types may be extremely complex


type particlebox
type(particle), dimension(:), pointer :: particles
real :: lx, ly, lz
end type particlebox

type(particlebox) :: box

allocate(box%particles(100))
box%particles(10)%mass = 1.0d0

Operators You can define your own operators with an interface block


module a
type point
real :: x, y
end type point

interface operator(.dist.)
module procedure calcdist
end interface

contains

function calcdist(p1, p2)
type(point) :: p1, p2
real :: calcdist

calcdist = sqrt((p1%x-p2%x)*2 + (p1%y-p2%y)*2)
end function calcdist

Dynamic memory Fortran90 introduced the concept of dynamic memory allocation and pointers. To dynamically allocate memory, an array must be declared allocatable


real, dimension(:,:), allocatable :: a

allocate(a(100,100))
...
deallocate(a)
Allocatable arrays can not be used within a derived data type. You need to use a pointer.

Pointers Unlike C style pointers, Fortran pointers point to a specific object. That object must be another pointer of the same type or a target.


real, dimension(100,100), target :: a
real, dimension(:,:), pointer :: b

b=>a
Now, both a and b refer to the same piece of memory. NOTE: b is NOT an array of pointers. It is a pointer to an array

More pointers You can allocate memory directly to a pointer as with an allocatable array


real, dimension(:,:), pointer :: a

nullify(a)
allocate(a(100,100))
...
deallocate(a)
A call to nullify(a) after an allocate will cause a memory leak.

Pointers to subsections You can use pointers to reference a subsection of an array. Be aware that this may have a serious performance impact.

real, dimension(100,100), target :: a
real, dimension(:,:), pointer :: b

b=>a(20:30,40:50)

The linked list One of the most useful features of derived types and pointers is the ability to create a dynamic structure called a link list.


type node
type(node), pointer :: next, prev
real, dimension(100,100) :: a
end type node

type(node), pointer :: ll, cur
integer :: i

allocate(ll)
ll%next => ll
ll%prev => ll

cur => ll

do i = 1, 10
allocate(cur%next)
cur%next%prev => cur
cur%next%next => ll
cur => cur%next
end do
This creates a dynamic list of arrays. Now, indexing b effectively strides through the array a

Linked list operations
Link lists can be grown


allocate(newnode)
newnode%prev => cur
newnode%next => cur%next
cur%next%prev => newnode
cur%%next => newnode
and shrunk

oldnode => cur
cur%prev%next => cur%next
cur%next%prev => cur%prev
cur => cur%next
deallocate(oldnode)

Fortran90 重载

, ,

在Fortran90中定义新的操作符,超载内部函数,固有操作符以及赋值号等。
下面这段代码定义了完整的有理数操作,其中超载’+’、’*’ 操作符和’=’赋值号,并定义了一个递归函数。保存为class_Rational.f90

 module class_Rational
  implicit none
  ! public everything but following private routines
  private :: gdd, reduce
  type Rational
     private
     integer :: num, den
  end type Rational
  
  interface assignment(=)
     module procedure equal_Integer; 
  end interface
  
  interface operator(+)
     module procedure add_Rational
  end interface
  
  interface operator(*)
     module procedure mult_Rational
  end interface
  
  interface operator(==)
     module procedure is_equal_to 
  end interface
  
 contains
 
  function add_Rational(a, b) result(c)
    type(Rational), intent(in) :: a, b
    type(Rational) :: c
    c%num = a%num * b%den + a%den * b%num
    c%den = a%den * b%den
    call reduce(c)
  end function add_Rational
  
  function convert(name) result(value)
    type(Rational),intent(in) :: name
    real :: value
    value = float(name%num) / name%den
  end function convert
  
  function copy_Rational(name) result(new)
    type(Rational), intent(in) :: name
    type(Rational) :: new
    new%num = name%num
    new%den = name%den
  end function copy_Rational
  
  subroutine delete_Rational(name)
    type(Rational), intent(inout)::name
    name = Rational(0,1)
  end subroutine delete_Rational
  
  subroutine equal_Integer(new, I)
    type(Rational), intent(out) :: new
    integer, intent(in) :: I
    new%num = I
    new%den =1
  end subroutine equal_Integer
  
  recursive function gdd(j,k) result(g)
    integer, intent(in) :: j, k
    integer :: g
    if (k==0) then
       g = j
    else
       g = gdd(k, modulo(j,k))
    end if
  end function gdd
  
  function get_Denominator(name) result(n)
    type(Rational), intent(in) :: name
    integer :: n
    n = name%den
  end function get_Denominator
  
  function get_Numerator(name) result(n)
    type(Rational), intent(in) :: name
    integer :: n
    n = name%num
  end function get_Numerator
  
  subroutine invert(name)
    type(Rational), intent(inout):: name
    integer:: temp
    temp = name%num
    name%num = name%den
    name%den = temp
  end subroutine invert
  
  function is_equal_to(a_given, b_given) result(t_f)
    type(Rational), intent(in):: a_given, b_given
    type(Rational) :: a, b
    logical :: t_f
    a = copy_Rational(a_given)
    b = copy_Rational(b_given)
    call reduce(a)
    call reduce(b)
    t_f = (a%num  b%num) .and. (a%denb%den)
  end function is_equal_to
  
  subroutine list(name)
    type(Rational), intent(in) :: name
    print *, name%num, ”/”, name%den
  end subroutine list
  
  function make_Rational(numerator, denominator) result(name)
    integer, optional, intent(in) :: numerator, denominator
    type(Rational) :: name
    name = Rational(0,1)
    if (present(numerator)) name%num = numerator
    if (present(denominator)) name%den = denominator
    if (name%den  0) name%den = 1
    call reduce(name)
  end function make_Rational
  
  function mult_Rational(a,b) result(c)
    type(Rational), intent(in) :: a, b
    type(Rational) :: c
    c%num = a%num *b%num
    c%den = a%den *b%den
    call reduce(c)
  end function mult_Rational
  
  function Rational_(numerator, denominator) result(name)
    integer, optional, intent(in) :: numerator, denominator
    type (Rational) :: name
    if ( denominator  0 ) then 
       name = Rational (numerator, 1)
    else 
       name = Rational (numerator, denominator)
    end if
  end function Rational_
  
  subroutine reduce (name) ! to simplest rational form
    type (Rational), intent(inout) :: name
    integer :: g ! greatest common divisor
    g = gdd (name % num, name % den)
    name % num = name % num/g
    name % den = name % den/g 
  end subroutine reduce
  
 end module class_Rational

主程序调用

include 'class_Rational.f90'
 program main
  use class_Rational
  implicit none
  type (Rational) :: x, y, z
  ! x = Rational(22,7) ! intrinsic constructor if public components
  x = Rational_(22,7) ! public constructor if private components
  write (*,'("public x = ")',advance='no'); call list(x)
  write (*,'("converted x = ", g9.4)') convert(x)
  call invert(x)
  write (*,'("inverted 1/x = ")',advance='no'); call list(x)
  x = make_Rational () ! default constructor
  write (*,'("made null x = ")',advance='no'); call list(x)
  y = 4 ! rational = integer overload
  write (*,'("integer y = ")',advance='no'); call list(y)
  z = make_Rational (22,7) ! manual constructor
  write (*,'("made full z = ")',advance='no'); call list(z)
  ! Test Accessors
  write (*,'("top of z = ", g4.0)') get_numerator(z)
  write (*,'("bottom of z = ", g4.0)') get_denominator(z)
  ! Misc. Function Tests
  write (*,'("making x = 100/360, ")',advance='no')
  x = make_Rational (100,360)
  write (*,'("reduced x = ")',advance='no'); call list(x)
  write (*,'("copying x to y gives ")',advance='no')
  y = copy_Rational (x)
  write (*,'("a new y = ")',advance='no'); call list(y)
  ! Test Overloaded Operators
  write (*,'("z * x gives ")',advance='no'); call list(z*x) ! times
  write (*,'("z + x gives ")',advance='no'); call list(z+x) ! add
  y = z ! overloaded assignment
  write (*,'("y = z gives y as ")',advance='no'); call list(y)
  write (*,'("logic y  x gives ")',advance='no'); print *, yx
  write (*,’(“logic y  z gives ")',advance='no'); print *, yz
  ! Destruct
  call delete_Rational (y) ! actually only null it here
  write (*,’(“deleting y gives y = ”)’,advance=’no’); call list(y)
end program main ! Running gives:
! public x = 22 / 7 ! converted x = 3.143
! inverted 1/x = 7 / 22 ! made null x = 0 / 1
! integer y = 4 / 1 ! made full z = 22 / 7
! top of z = 22 ! bottom of z = 7
! making x = 100/360, reduced x = 5 / 18
! copying x to y gives a new y = 5 / 18
! z * x gives 55 / 63 ! z + x gives 431 / 126
! y = z gives y as 22 / 7 ! logic y  x gives F
! logic y  z gives T ! deleting y gives y = 0 / 1

OOP in Fortran

, ,

Never read documents of Fortran90/95. So many new features are not clear to me. Recently, I read the book <<Object-Oriented Programming via Fortran 90/95>>.

also, read this Fortran 2003:完美还是虚幻?

! File: Fibonacci_Number.f90
! Fortran 90 OOP to print list of Fibonacci Numbers

module class_Fibonacci_Number
  implicit none
  public :: Print               ! member access
  private :: Add                ! member access
  type Fibonacci_Number         ! attribute
     private
     integer :: low, high, limit ! state variables & access
  end type Fibonacci_Number

contains
  function new_Fibonacci_Number(max) result (num) ! constructor
    implicit none
    integer, optional :: max
    type(Fibonacci_Number) :: num
    num = Fibonacci_Number(0,1,0)
    if (present(max)) num = Fibonacci_Number(0,1,max)
    !    num%exists = .true.
  end function new_Fibonacci_Number

  function Add (this) result (sum)
    implicit none
    type(Fibonacci_Number), intent(in) :: this
    integer :: sum
    sum = this%low + this%high
  end function Add


  subroutine Print(num)
    implicit none
    type(Fibonacci_Number), intent(inout) :: num
    integer :: j, sum
    if (num%limit < 0) return
    print *, 'M Fibonaci(M)'
    do j = 1, num%limit
       sum = Add(num)
       print *, j, sum
       num%low = num%high
       num%high = sum
    end do
  end subroutine Print
end module class_Fibonacci_Number

program Fibonacci
  use class_Fibonacci_Number  
  implicit none
  integer, parameter :: xend = 8
  type(Fibonacci_Number) :: num

  num = new_Fibonacci_Number(xend)
  call Print(num)

end program Fibonacci