Poisson Solver 2

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

Poisson solver

Ovdje sam raspisao detaljno objašnjenje Poissonova solvera kao najjednostavnijeg solvera (što
unatoč tome nije bilo jednostavno). Sljedeći je solver koji se tiče magnetodinamike nakon kojeg,
nadam se, mogu početi pisati vlastiti kod.
Svaki solver u Elmeru počinje sa sljedećom formulacijom globalnih varijabli.
TYPE(Solver_t) :: Solver !struktura podataka u koju su spremljeni podaci vezani za solver

TYPE(Model_t) :: Model !struktura podataka u koju su spremljeni podaci vezani za model

REAL(KIND=dp) :: dt !infinitezimalni vremenski pomak

LOGICAL :: TransientSimulation !logička varijabla koja ako je 1 će kasnije uzrokovati

!izračun tranzijentnog stanja simulacije

Lokalne varijable modula


LOGICAL :: AllocationsDone = .FALSE., Found, PosEl, NegEl

AlocationsDone je logička varijabla koja je 1 ako je alokacija memorije za lokalnu matricu i lokalni
rhs-vektor napravljena. PosEl i NegEl svojom istinitošću potvrđuju da se radi o… elektrodi.
TYPE(Element_t),POINTER :: Element

Element je struktura element_t a u sebi sadrži između ostalog integere BodyId, NDOFs, BDOFs,
DGDOFs??, pokazivače na integere NodeIndexes, EdgeIndexes, FaceIndexes , itd. te pokazivač
TYPE koji je pokazivač na strukturu ElementType_t, a koja u sebi sadrži opis tipa elementa:
integer ElementCode (numerički kod elementa 303, 306, 404, 827,… – prva znamenka predstavlja
vrstu geometrijskog lika ili tijela (obično odgovara broju vrhova lika ili tijela: 3=trokut,
4=kvadrilateral, 5=tetraedar, 6=piramida, 7=klin, 8=kocka), a druga broj čvorova/nodes), integere
NumberOfNodes, NumberOfEdges, NumberofFaces, Dimension (1, 2 ili 3), BasisFunctionDegree
(linerna ili kvadratna bazna funkcija tj. prvi ili drugi stupanj bazne funkcije (funkcije oblika)).
INTEGER :: n, nb, nd, t, istat, active

Varijabla n čuva broj čvorova aktivnog elementa. Varijabla nb čuva broj stupnjeva slobode
aktivnog elementa. Varijabla nd čuva broj bubble stupnjeva slobode. Varijabla active čuva ukupan
broj aktivnih elemenata.
TYPE(Mesh_t), POINTER :: Mesh

Mesh je pokazivač na strukturu podataka Mesh_t koja između ostalog sadrži


TYPE(ValueList_t), POINTER :: BodyForce, BC

Varijabla BodyForce je pokazivač na ValueList_t strukturu podataka koja sadrži podatke o


BodyForce.
Varijabla BC je analogno varijabli BodyForce pokazivač na Valuelist_t strukturu podataka koja
sadrži podatke o BoundaryCondition.
REAL(KIND=dp), ALLOCATABLE :: STIFF(:,:), LOAD(:), FORCE(:)

STIFF(:,:) je stiffness matrica trenutno aktivnog elementa, LOAD(:) je vektor u kojemu se nalaze
vrijednosti BodyForce (npr. naboja) za trenutno aktivni element, a FORCE(:) je rhs-vektor koji se
preračuna iz LOAD(:) vektora i predstavlja desnu stranu sustava V(:)*STIFF(:,:)=FORCE(:). Sve tri
varijable su spremljene uz AllocationsDone varijablu što znači da se alokacija prostora za lokalne
(elementarne) matrice i vektore obavlja samo jednom.
SAVE STIFF, LOAD, FORCE, AllocationsDone

IF (.NOT.ASSOCIATED(Solver % Matrix)) RETURN !provjera jesu li strukturi matrix_t unutar

!strukture solver_t pridružen ????????????

Alokacija
Kao što je već rečeno, alokacija prostora za lokalne matrice i vektore se obavlja samo jednom.
Najprije se pomoću GetMesh() funkcije lokalno definirana varijabla (pokazivač ) pridruži na
trenutno aktivni mesh.
Mesh => GetMesh()

Zatim se obavlja alokacija:


IF ( .NOT. AllocationsDone ) THEN ! AllocationsDone je pod SAVE, pa je ovo samo jednom istinito

N = Solver % Mesh % MaxElementDOFs !MaxelementDOFs da bude dovoljno velika za svaki element

ALLOCATE( FORCE(N), LOAD(N), STIFF(N,N), STAT=istat )

IF ( istat /= 0 ) THEN !u slučaju errora

CALL Fatal( 'PoissonSolve', 'Memory allocation error.' )

END IF

AllocationsDone = .TRUE. ! ostat će TRUE ubuduće jer je pod SAVE

END IF

Glavni dio koda – izgradnja FEM sustava jednadžbi


Active = GetNOFActive()

Funkcija GetNOFActive() vraća broj aktivnih elemenata za trenutni solver.


CALL DefaultInitialize()

Rutina DefaultInitialize() obavlja inicijalizaciju matrične jednadžbe (cijele matrix_t strukture)


vezane za trenutno aktivni solver na vrijednost nula pozivanjem rutine InitializeToZero().
Nakon toga slijedi DO-petlja koja obavlja izgradnju lokalne matrice i vektora za svaki od aktivnih
elemenata, tj. petlja ide od 1 do Active (broj aktivnih elemenata trenutnog solvera).
DO t=1,Active

Element => GetActiveElement(t)

n = GetElementNOFNodes() !broj čvorova ovog elementa

nd = GetElementNOFDOFs() !broj stupnjeva slobode ovog elementa

nb = GetElementNOFBDOFs() !broj bubble-stupnjeva slobode ovog elementa

LOAD = 0.0d0 ! incijalizacija vektora LOAD

BodyForce => GetBodyForce()

IF ( ASSOCIATED(BodyForce) ) & !ako je ovom elementu (nj. čvorovima) pridružen naboj

Load(1:n) = GetReal( BodyForce, 'Source', Found ) !dohvaća vrijednost naboja

CALL LocalMatrix( STIFF, FORCE, LOAD, Element, n, nd+nb ) !izgradnja lokalne matrice

CALL LCondensate( nd, nb, STIFF, FORCE )

CALL DefaultUpdateEquations( STIFF, FORCE )

END DO

Funkcija GetActiveElement() vraća trenutno aktivni element čiji je redni broj, među aktivnim
elementima za ovaj solver, jednak integeru t. Indeksi svih aktivnih elementa za ovaj solver su
spremljeni u strukturi oblika solver_t (index=Solver%ActiveElements(t)). Preko indeksa elementa
t, funkcija pronalazi trenutno aktivni element (Element => Solver % Mesh % Elements( ind ))te ga
vraća i pridružuje lokalnoj varijabli (pokazivaču) Element.
Funkcija GetElementNOFNodes() vraća broj čvorova trenutno aktivnog elementa Element.
Unutar strukture trenutno aktivnog elementa Element (tipa Element_t) funkcija pristupa
strukturi TYPE (struktura tipa ElementType_t) koja opisuje trenutno aktivni element i u kojoj se
nalazi između ostalog integer NumberOfNodes (n = CurrElement % TYPE % NumberOfNodes).
Funkcija GetElementNOFDOF() vraća broj stupnjeva slobode DOFs trenutno aktivnog elementa
Element.
Funkcija GetElementNOFBDOFs vraća broj bubble-stupnjeva slobode trenutno aktivnog
elementa Element.
Funkcija GetBodyForce() preko interne funkcije GetBodyForceId(), koja određuje kojem tijelu
(Element%BodyId ) pripada trenutno aktivni element i ako je tom tijelu pridružen ikakav
BodyForce (npr. naboj) određuje koji ID taj BodyForce ima (dodijeljen mu u SIF-file), te joj ga vraća
pa funkcija GetBodyForce() zatim pronalazi listu podataka ValueList koja tom BodyForceu s tim
ID-om pripada u trenutnom modelu CurrentModel te tu listu podataka vraća u pozivnu funkciju.
Nakon što je putem GetBodyForce() te GetReal() funkcija dobiven vektor iznosa naboja u
čvorovima trenutnog elementa, poziva se rutina LocalMatrix() kojom se izgrađuje matrična
jednadžba nad trenutnim elementom, tj. određuje se matrica veza (STIFF- stiffness matrix) i
vektor FORCE koji predstavlja desnu stranu matrične jednadžbe.
Nakon što su izgrađeni matrica STIFF i vektor FORCE, poziva se interna Elmerova rutina
DefaultUpdateEquation() čija je osnovna zadaća izgradnja globalne STIFF matrice i FORCE vektora
na osnovu lokalnih matrica, tj. matrica svakog od aktivnih elemenata domene (glavna rutina
unutar ove rutine je UpdateGlobaleEquationes() koja zapravo obavlja spajanje lokalnih matrica i
vektora).

GRANIČNI ELEMENTI
Analogno dosadašnjem dijelu koda koji se bavio slobodnim (aktivnim) elementima, pristupa se i
graničnim elementima (boundary elements).
DO t=1, Solver % Mesh % NumberOfBoundaryElements !petlja po svim graničnim elementima

Element => GetBoundaryElement(t) !pokazivaču se pridružuje jedan granični element

IF ( .NOT.ActiveBoundaryElement() ) CYCLE !provjerava je li granični element aktivan tj.

!pripada domeni trenutnog solvera

n = GetElementNOFNodes() !vraća broj čvorova trenutnog elementa

IF ( GetElementFamily() == 1 ) CYCLE !ako je ElementCode/100==1 element je 0-Dimenzije

BC => GetBC() !u BC je spremljena ValueList graničnih uvjeta trenutnog modela

FORCE = 0.0d00

STIFF = 0.0d00

PosEl = .False.

NegEl = .False.

PosEl = GetLogical(BC,'Positive Electrode', Found) !granični element čini (+) elektrodu?

PosEl = GetLogical(BC,'Positive Electrode', Found) !granični element čini (-) elektrodu?

LOAD = 0._dp

IF (PosEl) LOAD = 1._dp !granični element pripada +elektrodi => load=1

IF (NegEl) LOAD = -1._dp !granični element pripada +elektrodi => load=-1

IF (Solver % Variable % name == 'w')

CALL BoundaryCondition(LOAD, FORCE, Element, n) !rutina analogna LocalMatrix (za FORCE)

END IF

CALL DefaultUpdateEquations( STIFF, FORCE ) !dodavanje lokalnog FORCE vektora globalnom

END DO
GetBC() je analogna funkciji GetBodyForce(), samo što dobavlja vrijednosti potencijala na granici
(boundary condition) domene, tj. za čvorove graničnog elementa.
Rutina GetBoundaryConditiones() je analogna rutini LocalMatrix, ali izgrađuje FORCE vektor za tu
jednadžbu.

Rutina LocalMatrix
U ovoj se (najvažnijoj) rutini izgrađuju lokalna matrica STIFF(:,:) i lokalni vektor FORCE(:).
SUBROUTINE LocalMatrix( STIFF, FORCE, LOAD, Element, n, nd ) !deklaracija

ARGUMENTI RUTINE:
REAL(KIND=dp) :: STIFF(:,:), FORCE(:), LOAD(:)

INTEGER :: n, nd !n je broj čvorova elementa, a nd broj DOFs elementa

TYPE(Element_t), POINTER :: Element !trenutno aktivni element

LOKALNE VARIJABLE:
INTEGER :: i,t !potrebni za DO petlje

LOGICAL :: Stat !rezultat funkcije ElementInfo – ako je False element je degeneriran

TYPE(GaussIntegrationPoints_t) :: IP !struktura sadrži integracijske točke (integration points)

Struktura podataka GaussIntegrationPoints_t sadrži integer N kojemu je pridružen broj točaka u


kojima će se računati vrijednosti funkcije (integration points), te sadrži vektore u(:), v(:), w(:) koji
su dugački upravo N i predstavljaju lokalne koordinate integracijskih točaka (u za 1D; u,v za 2D;
u,v,w za 3D). Struktura je prikazana u nastavku:
TYPE GaussIntegrationPoints_t

INTEGER :: N

REAL(KIND=dp), POINTER CONTIG :: u(:),v(:),w(:),s(:)

END TYPE GaussIntegrationPoints_t

Struktura pored toga sadrži i vektor s(:) koji je također dugačak N i za svaku integracijsku točku
sadrži težinu koja pripada toj integracijskoj točki u ukupnom doprinosu pri numeričkoj integraciji
nad elementom.
REAL(KIND=dp) :: Basis(nd),dBasisdx(nd,3),DetJ,LoadAtIP

Realni vektor Basis(nd) će biti zadužen za spremanje vrijednosti svih baznih funkcija (shape
functiones) u jednoj te istoj točki unutar elementa (IP=(x0,y0) - integration point) – svakom
stupnju slobode pripada jedna bazna funkcija pa je zato vektor dugačak nd.

Basis  1 ( IP) 2 ( IP) 3 ( IP)


Realni vektor dBasisdx(nd,3) zadužen je za spremanje prvih derivacija svih baznih funkcija u istoj
točki (integration point). Primjerice, za tetraedar element s četiri stupnja slobode:

 1 1 1 


 x y z 
 
  2  2  2 
 x y z 
dBasisdx   
  3  3  3 
 x y z 
 
  4  4  4 
 x y z 

Varijabla LoadAtIP čuva vrijednost BodyForce (naboja) u konkretnoj, trenutno aktivnoj
integracijskoj točki IP=(x0,y0) unutar elementa.
Varijabla DetJ je varijabla kojoj se pridružuje vrijednost volumena (površine u slučaju 2D)
elementa. Izračunava se kao DetJ=sqrt(det(JTJ)) gdje J predstavlja matricu koordinata čvorova tj.
vektorski produkt stranica
elementa, koja općenito nije kvadratna matrica, pa stoga nema determinantu. Ipak, kako bi se
odredio volumen tog elementa, koristi se gornja formula koja posredno zaobiđe problem
nekvadratnosti matrice jer za neku općenitu kvadratnu matricu vrijedi det(ATA)= det(AT)det(A) i
još det(AT)=det(A), pa se u slučaju neke općenite kvadratne matrice dobije sqrt(det(ATA))=detA.
TYPE(Nodes_t) :: Nodes

SAVE Nodes

Varijabla Nodes je struktura Nodes_t koja između ostalog sadrži integer NumberOfNodes te
realne varijable (pokazivače na vektore) x(:), y(:), z(:) koje čuvaju globalne koordinate čvorova.
Veličina tih vektora je jednaka broju čvorova NumberOfNodes.
Rutina GetElementNodes() preko varijable (argumenta) Nodes vraća (sprema) koordinate
čvorova trenutnog elementa.
CALL GetElementNodes( Nodes )

STIFF = 0.0d0 !inicijalizacija matrice

FORCE = 0.0d0 !inicijalizacija matrice

NUMERIČKA INTEGRACIJA
Funkcija GaussPoints(), za dani element proslijeđen u funkciju kao argument, vraća gaussove
integracijske točke u strukturi tipa GaussIntegrationPoints_t (u ovom slučaju to je varijabla IP).
IP = GaussPoints( Element )
Nakon što su prikupljene lokalne koordinate svake integracijske točke i težine svake integracijske
točke (važnost integracijske točke u smislu doprinosa ukupnom integralu u odnosu na ostale
integracijske točke) konačno se ulazi najvažniji dio cijelog solvera a to je numerička integracija
(numerička integracija slabe formulacije Poissonove jednadžbe) nad trenutno aktivnim
elementom. Prije nego što se krene u integraciju potrebno je objasniti vrlo važnu funkciju
ElementInfo() čiji su argumenti varijabla Element (informacije o trenutnom elementu), Nodes
(globalne koordinate čvorova trenutnog elementa), IP%U(t) (prvu lokalnu koordinatu
integracijske točke), IP%V(t) drugu koordinatu, IP%W(t) treću koordinatu, te detJ, Basis i BasisdX
koji su izlazni argumenti. Funkcija ElementInfo() će preko detJ vratiti volumen elementa, preko
Basis će vratiti vektor vrijednosti svih baznih funkcija elementa (stoga dužina vektora odgovara
broju stupnjeva slobode) u integracijskoj točki čiji se lokalne koordinate (IP%U(t), IP%V(t),
IP%W(t)), dok će preko dBasisdx vratiti sve prve derivacije baznih funkcija u istoj integracijskoj
točki (gornja matrica). Funkcija može opcionalno vraćati još nekoliko podataka (druge derivacije
baznih funkcija, stupnjeve baznih funkcija,…) ali u ovom solveru te opcije nisu korištene.
Integracija se obavlja kroz DO-petlju, po svim integracijskim točkama unutar elementa (dakle, od
1 do broja integracijskih točaka). Za svaku od integracijskih točaka se dakle iznova poziva funkcija
ElementInfo() preko koje se dobiva detJ, te vektor Basis i matrica dBasisdx za tu točku.
Slaba formulacija Poissonove jednadžbe nad elementom s N čvorova glasi:
1
 u  d       d 

e i

e i za i  V0 (1)

N
ue   uei i (2)
i

N
e   ei i (3)
i

Iz gornjih jednadžbi slijedi opći oblik jednog od N×N pribrojnika s lijeve strane znaka jednakosti
linearnog sustava N jednadžbi.

 (u  ) d 

ei i j za i, j = 0, 1, 2,...N (4)

Odnosno, jedan od N×N koeficijenata matrice veza (stiffness matrix) će biti

Cij    i  j d  za i, j = 0, 1, 2,...N (5)


Analogno prethodna dva izraza, jedan od N×N pribrojnika s desne strane znaka jednakosti
linearnog sustava N jednadžbi bi glasio

     d 

ei i j za i, j = 0, 1, 2,...N , (6)
tj. jedan od N×N koeficijenata matrice s desne strane znaka jednakosti bi bio

Tij    i j d  za i, j = 0, 1, 2,...N (7)


No, u ovom kodu se ne koristi taj pristup (ne koriste se eksplicitno izrazi (6) i (7) ) nego se odmah,
bez daljnjeg raščlanjivanja, izravno koristi integral na desnoj strani izraza (1). Budući da je vektor
tereta (LOAD) ρe=[ ρe1, ρe2,… ρei] već poznat (dobiven ranije u kodu, prije pozivanja LocalMatrix
rutine, preko funkcije GetBodyForce()), računa se iznos naboja ρ(IP) u trenutnoj integracijskoj
točki trenutnog elementa

LoadAtIP   e1 e 2 ... eN   1 ( IP)  2 ( IP) ...  N ( IP) 


T
(8)

Time je efektivno dobiven ρe iz (1) s tim da se integral u (1) u tom slučaju računa samo po dijelu
domene Ω, što je određeno iznosom težine trenutne integracijske točke IP%s(t). Cijeli integral, s
desne strane iz (1), se računa dalje u zadnjem izrazu u integracijskoj petlji kao vektor FORCE.
Dakle, umnožak težine integracijske točke s volumenom ( IP%s(t) * detJ ) određuje dio Ω u
integralu. To se dalje množi s vrijednošću naboja u toj integracijskoj točki LoadAtIP a zatim se sve
to množi s vektorom Basis u kojemu su sadržane bazne funkcije svih stupnjeva slobode trenutnog
elementa (i=1,2,…NDOFs), kao što je i predviđeno izrazom (1) pa se dobiva vektor FORCE. Točnije,
dobije se samo dio vektora FORCE koji odgovara integralu po ( IP%s(t) * detJ ) dijelu volumena Ω.
Da bi se dobio konačan vektor FORCE, potrebno je istim postupkom izračunat integral i za ostatak
domene Ω, tj. u svim ostalim integracijskim točkama trenutnog elementa kroz DO-petlju te
sumirati dobivene vektore. Otud u izrazu Force(1:nd) = Force(1:nd) + ….
DO t=1,IP % n

stat = ElementInfo(Element, Nodes, IP % U(t), IP % V(t), IP % W(t), detJ, Basis, dBasisdx)

LoadAtIP = SUM( Basis(1:n) * LOAD(1:n) ) !iznos naboja u integracijskoj točki

STIFF(1:nd,1:nd) = STIFF(1:nd,1:nd) + IP % s(t) * DetJ * &

MATMUL( dBasisdx, TRANSPOSE( dBasisdx ) ) !množenje matrica

FORCE(1:nd) = FORCE(1:nd) + IP % s(t) * DetJ * LoadAtIP * Basis(1:nd)

END DO

Preostalo je još samo odrediti STIFF matricu, tj. matricu [Ce] čiji se elementi Cij računaju izrazom
(5). Svakoj integracijskoj točki u DO petlji odgovara određena težina u doprinosu integralu s lijeve
strane u (1). Taj doprinos je određen umnoškom ( IP%s(t) * detJ ). Množenjem matrice dBasisdx
s transponiranom matricom dBasisdx dobije se NDOFs×NDOFs matrica čiji su elementi zapravo
umnošci gradijenata baznih funkcija trenutnog elementa u trenutnoj integracijskoj točki, tj.
podintegralne funkcije integrala (5). Množenjem dobivene matrice umnožaka gradijenata s
dijelom volumena Ω ( IP%s(t) * detJ ) dobiva se dio integrala u (1). Prolaskom kroz DO petlju, tj.
sve integracijske točke trenutnog elementa, te zbrajanjem dobivenih vrijednosti iz svake iteracije
(otud izraz STIFF(1:nd,1:nd)=STIFF(1:nd,1:nd)+… ) dobiva se konačni integral s lijeve strane iz (1)
po cijeloj domeni Ω. Zapis umnoška matrice dBasisdx s transponiranom matricom dBasisdx glasi

  2   2   2       
 1    1    1  1 2
 1 2
 1 2
...
 x   y   y  x x y y z z 
       
dBasisdx  dBasisdxT   2 1  2 1  2 1 ... 
 x x y y z z 
... 
 
 

Time je opisana rutina LocalMatrix kojom se računa matrična jednadžba nad elementom

Ce   U    B  STIFF  U   FORCE


Gdje je vektor [U]=[ue1 ue2 …ueN] vektor nepoznanica koje odgovaraju potencijalima čvorova, tj.
koje predstavljaju stupnjeve slobode trenutnog elementa.

Završetak koda
CALL DefaultFinishAssembly() !Završno asembliranje globalne matrične jednadžbe

CALL DefaultDirichletBCs() !postavljanje Dirichletovih uvjeta

Norm = DefaultSolve() !pozivanje internog solvera za rješavanje matrične jednadžbe

Funkcija DefaultSolve() je interni Elmerov solver za rješavanje konačne matrične jednadžbe.

You might also like