Professional Documents
Culture Documents
Poisson Solver 2
Poisson Solver 2
Poisson Solver 2
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
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
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
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()
END IF
END IF
CALL LocalMatrix( STIFF, FORCE, LOAD, Element, n, nd+nb ) !izgradnja lokalne matrice
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
FORCE = 0.0d00
STIFF = 0.0d00
PosEl = .False.
NegEl = .False.
LOAD = 0._dp
END IF
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(:)
LOKALNE VARIJABLE:
INTEGER :: i,t !potrebni za DO petlje
INTEGER :: N
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.
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 )
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)
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
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
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
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
Završetak koda
CALL DefaultFinishAssembly() !Završno asembliranje globalne matrične jednadžbe