· quatro anos de estudo de física, ... descrita pela eletrodinâmica clássica. ... se 1w de...

105
TEO VICTOR RESENDE DA SILVA SOLUÇÃO DAS EQUAÇÕES DE BLOCH ÓPTICAS PARA SISTEMAS ATÔMICOS DE DOIS E TRÊS NÍVEIS UTILIZANDO GPUS JI-PARANÁ, RO JULHO DE 2017

Upload: phunghuong

Post on 14-Jan-2019

217 views

Category:

Documents


0 download

TRANSCRIPT

TEO VICTOR RESENDE DA SILVA

SOLUÇÃO DAS EQUAÇÕES DE BLOCH ÓPTICAS PARA SISTEMAS ATÔMICOSDE DOIS E TRÊS NÍVEIS UTILIZANDO GPUS

JI-PARANÁ, ROJULHO DE 2017

TEO VICTOR RESENDE DA SILVA

SOLUÇÃO DAS EQUAÇÕES DE BLOCH ÓPTICAS PARA SISTEMAS ATÔMICOSDE DOIS E TRÊS NÍVEIS UTILIZANDO GPUS

Trabalho de Conclusão de Curso apresentadoao Departamento de Física de Ji-Paraná,Universidade Federal de Rondônia, Campus deJi-Paraná, como parte dos quesitos para aobtenção do Título de Bacharel em Física, soborientação do Prof. Dr. Marco Polo Moreno deSouza

JI-PARANÁ, ROJULHO DE 2017

FUNDAÇÃO UNIVERSIDADE FEDERAL DE RONDÔNIACAMPUS DE JI-PARANÁ

DEPARTAMENTO DE FÍSICA DE JI-PARANÁ – DEFIJI

ATA DE AVALIAÇÃO DO TRABALHO DE CONCLUSÃO DE CURSO DO CURSODE BACHARELADO EM FÍSICA.

Aos ___ dias do mês de julho do ano de 2017, às ________, no Auditório do Campus da Unir

de Ji-Paraná, reuniu-se a Banca Julgadora composta pelo professor orientador Dr. Marco Polo

Moreno de Souza e pelos examinadores Prof. Dr. Walter Trennepohl Júnior e Prof. Dr.

Ricardo de Sousa Costa, para avaliarem o Trabalho de Conclusão de Curso, do Curso de

Bacharelado em Física, intitulado “SOLUÇÃO DAS EQUAÇÕES DE BLOCH ÓPTICAS

PARA SISTEMAS ATÔMICOS DE DOIS E TRÊS NÍVEIS UTILIZANDO GPUS”, do

discente Teo Victor Resende da Silva. Após a apresentação, o candidato foi arguido pelos

integrantes da Banca Julgadora por _____ minutos. Ao final da arguição, a Banca Julgadora,

em sessão reservada, _________________ o candidato com nota _____, em uma avaliação de

0 (zero) a 10 (dez). Nada mais havendo a tratar, a sessão foi encerrada às ___ horas e ____

minutos, dela sendo lavrada a presente ata, assinada por todos os membros da Banca

Julgadora.

_______________________________________________________

Prof. Dr. Marco Polo Moreno de Souza – DEFIJI/CJP/UNIROrientador

_______________________________________________________

Prof. Dr. Walter Trennepohl Júnior – DEFIJI/CJP/UNIR

_______________________________________________________

Prof. Dr. Ricardo de Sousa Costa – DEFIJI/CJP/UNIR

4

AGRADECIMENTOS

A todo corpo docente da Unir pelo aprendizado proporcionado até aqui em quase

quatro anos de estudo de Física, Matemática e ciência em geral, com gratidão especial

ao orientador deste trabalho, Prof. Marco Polo, pelo profissionalismo e disposição carac-

terísticos que permitiram a conclusão da monografia e o entendimento de diversos temas

intrincados.

Aos colegas de curso, quase todos mais novos que eu, mas que me acolheram como

se fosse jovem como eles.

A James Hetfield, John Paul Jones, Robert Plant, Jimmy Page, David Gilmour,

Roger Waters, Esperanza Spalding, Brian May e, in memorian, Freddy Mercury e Ch-

ris Cornell pelas músicas que tocavam ao fundo durante a produção do texto, ou nos

momentos de descanso entre parágrafos.

Aos muitos divulgadores e divulgadoras que despertaram o meu interesse pela

ciência nos anos 1990, luzes de razão que nos atuais tempos de obscurantismo crescente

se fazem talvez ainda mais necessárias.

5

Your father’s lightsaber. This is the weapon of a Jedi Knight. Not as clumsy

or random as a blaster. An elegant weapon, for a more civilized age.—Obi-Wan Kenobi, para Luke Skywalker, Uma Nova Esperança

6

RESUMO

As equações de Bloch ópticas descrevem a interação da matriz densidade com um campo

eletromagnético ao longo do tempo. Abordamos neste trabalho a solução dessas equações

para sistemas atômicos de dois e três níveis interagindo com um trem de pulsos de laser

ultracurtos. Utilizamos o método Runge-Kutta de 4a ordem para solução dos sistemas

de equações diferenciais para o problema. Adotamos parâmetros compatíveis com vapor

atômico de rubídio. Como o deslocamento Doppler é um efeito importante em um vapor

atômico, efetuamos a distribuição Maxwell-Boltzmann das velocidades. Para um perfil

Doppler adequado do vapor atômico de rubídio na temperatura ambiente a faixa de velo-

cidades calculadas vai de -600 a 600 m/s. Também estudamos um sistema de três níveis

do tipo Λ, variando a taxa de repetição do laser pulsado. A solução computacional destes

últimos dois casos se torna custosa e demorada para um programa sequencial comum, mas

tem uma natureza obviamente paralelizável. O uso de unidades de processamento gráfico

(GPUs) para problemas computacionais paralelizáveis tem se difundido nos últimos anos

nas mais diversas áreas da ciência, como por exemplo em problemas físicos envolvendo

simulações de Monte Carlo. Comparamos o desempenho das soluções das equações de

Bloch na forma tradicional sequencial e suas alternativas paralelas na plataforma CUDA,

com placas de vídeo nVidia. O uso dessa tecnologia aplicada a problemas físicos paraleli-

záveis pode significar ganhos de tempo da ordem de dezenas ou até centenas, dependendo

da natureza e do tamanho do problema.

Palavras-chave: equações de Bloch; transições em vapor atômico; paralelização na GPU

7

LISTA DE TABELAS

4.1 Configuração das camadas eletrônicas em átomos alcalinos. . . . . . . . . . 34

6.1 GPUs nVidia utilizadas nos testes. . . . . . . . . . . . . . . . . . . . . . . 58

6.2 Máquinas distintas e suas combinações CPUxGPU. . . . . . . . . . . . . . 58

6.3 Comparações CPUxGPU das máquinas em operação e o respectivo tama-

nho do array de velocidades a partir do qual o tempo de execução na GPU

é menor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

6.4 Fator de ganho de tempo da GPU em relação à CPU no cálculo dos dados

de variação da frequência. . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

8

LISTA DE FIGURAS

2.1 Distribuição Maxwell-Boltzmann do isótopo 85Rb . . . . . . . . . . . . . . 22

2.2 Transição de dois fótons . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.3 Sistema atômico de três níveis com EIT . . . . . . . . . . . . . . . . . . . . 26

3.1 Campo elétrico para um trem de pulsos . . . . . . . . . . . . . . . . . . . . 30

3.2 Ilustração de um pulso com envoltória e largura de 100 fs. . . . . . . . . . 31

3.3 Transformada de Fourier do pulso. . . . . . . . . . . . . . . . . . . . . . . 31

4.1 Energia de ionização em função do número atômico Z . . . . . . . . . . . . 35

4.2 Estruturas fina e hiperfina do rubídio. . . . . . . . . . . . . . . . . . . . . . 37

4.3 Representação de um sistema atômico de três níveis do tipo Λ. . . . . . . . 41

4.4 Representação de um sistema atômico de três níveis tipo cascata. . . . . . 43

5.1 Estrutura simplificada de uma CPU . . . . . . . . . . . . . . . . . . . . . . 46

5.2 Estrutura simplificada de um cluster de computadores para processamento

paralelo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

5.3 Esquema simplificado de uma GPU atual, com hieraquia de memória dos

SMs e interface com a CPU. . . . . . . . . . . . . . . . . . . . . . . . . . . 48

5.4 Esquema simplificado da distribuição de blocos por multiprocessador de

uma GPU. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

6.1 População ρ22 em função do tempo, com variações de Ω0. Utilizados como

parâmetros γ22 = 2π × 5MHz, δ = 0, γ12 = γ22/2, valores realistas para a

transição 5S → 5P do rubídio. . . . . . . . . . . . . . . . . . . . . . . . . . 53

6.2 População ρ22 em função do tempo, com variações de δ . . . . . . . . . . . 54

6.3 Variação temporal das populações ρ22 e ρ33 . . . . . . . . . . . . . . . . . . 55

6.4 Distribuição das populações ρ22 e ρ33 por velocidade . . . . . . . . . . . . . 56

6.5 Comparativo entre tempos de execução na CPU e na GPU variando-se o

número de pulsos do laser . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

6.6 Evolução do tempo de execução variando-se o número de threads na GPU

e o número de iterações na CPU. . . . . . . . . . . . . . . . . . . . . . . . 60

6.7 Tempo de execução em função do número de threads executadas na GPU. . 61

9

6.8 Tempo de execução em função da proporção threads/bloco . . . . . . . . . 62

6.9 Tempo de execução em função do número threads para um bloco. . . . . . 62

6.10 Valores absolutos da diferença entre a solução da distribuição população

ρ22 entre a CPU e a GPU. . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

6.11 Tempo de execução em função do tamanho do array de velocidades para

i5 4460 e dois exemplos extremos: a placa de menor poder computacional

dos testes, GT210, e a superior GTX 760 Ti. . . . . . . . . . . . . . . . . . 64

6.12 Tempo de execução para o problema em cada hardware utilizado. . . . . . 66

6.13 População ρ33 e σ12 em função da variação da frequência de repetição . . . 67

10

CONTEÚDO

1 Introdução 17

2 Transições atômicas 21

2.1 Níveis de energia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.2 Interação com radiação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.3 Taxas de transição e regras de seleção . . . . . . . . . . . . . . . . . . . . . 23

2.4 Interação com dois fótons . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.5 Transparência eletromagneticamente induzida . . . . . . . . . . . . . . . . 25

3 Lasers pulsados 27

3.1 Histórico do laser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3.2 Emissão estimulada, ganho de laser e inversão de população . . . . . . . . 27

3.3 Laser pulsado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

3.3.1 Representação do campo elétrico . . . . . . . . . . . . . . . . . . . 29

4 Sistemas atômicos 33

4.1 Átomos alcalinos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

4.2 Estrutura fina e hiperfina . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

4.3 O átomo de rubídio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.4 As equações de Bloch ópticas . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.5 Sistema de dois níveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.6 Sistema de três níveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.6.1 Tipo Λ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

4.6.2 Tipo cascata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

5 Paralelismo em unidades de processamento gráfico 45

5.1 Programação serializada . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

5.1.1 Arquitetura da CPU . . . . . . . . . . . . . . . . . . . . . . . . . . 45

5.2 Programação paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

5.3 Paralelismo em placas gráficas . . . . . . . . . . . . . . . . . . . . . . . . . 47

5.3.1 Arquitetura da GPU . . . . . . . . . . . . . . . . . . . . . . . . . . 48

5.3.2 Programação paralela em CUDA-C . . . . . . . . . . . . . . . . . . 49

11

6 Resultados 53

6.1 Dinâmica de populações em átomos de três níveis em cascata . . . . . . . . 53

6.2 Solução na GPU para átomos de dois níveis . . . . . . . . . . . . . . . . . 57

6.2.1 Publicações e participações em eventos . . . . . . . . . . . . . . . . 64

6.3 Solução na GPU para átomos de três níveis do tipo Λ . . . . . . . . . . . . 64

7 Conclusões 69

Apêndice 1: Código fonte C de programa para solução das equações de

Bloch em um sistema atômico de três níveis 75

Apêndice 2: Código fonte C de programa que distribui as populações por

velocidade em um sistema atômico de três níveis 81

Apêndice 3: Código fonte C de programa para medições na CPU envol-

vendo a solução para sistemas de dois níveis 87

Apêndice 4: Código fonte CUDA-C de programa para medições na GPU

envolvendo a solução para sistemas de dois níveis 91

Apêndice 5: Banner apresentado no ENF 2016 96

Apêndice 6: Resumo da apresentação no ENF 2016 97

Apêndice 6: Resumo da apresentação para o grupo de pesquisa Estrutura

da Matéria e Física Computacional 99

Anexo 1: Aceitação ENF 2016 101

Anexo 2: Código fonte CUDA-C para a solução para sistemas de três níveis

tipo Λ na GPU 103

Anexo 3: Código fonte C++ para a solução para sistemas de três níveis

tipo Λ na CPU 113

12

1 INTRODUÇÃO

A interação dos átomos com radiação é um tema estudado desde o início do século

XX e os primórdios da Mecânica Quântica. O modelo atômico de Bohr já propunha níveis

quantizados de energia para o átomo de hidrogênio. Modelos mais elaborados com base

na equação de Schrödinger chegaram a resultados semelhantes, embora com as devidas

correções posteriores que não eram compatíveis com o modelo simples de Bohr [1, 2].

Os conceitos de emissão e absorção já eram propostos teoricamente por Einsten

desde a década de 1910. Sua aplicação prática nas décadas de 1950 e 1960 permitiu o

surgimento do laser, que ampliou ainda mais as possibilidades de estudo da interação dos

sistemas atômicos com campos eletromagnéticos, inclusive com efeitos coerentes. Os lasers

pulsados e sua alta potência de emissão contribuíram ainda mais com a área, especialmente

os lasers mode-locked com largura temporal dos pulsos da ordem de femtossegundos [3, 4].

A dinâmica de sistemas atômicos pode ser descrita pelo formalismo da matriz den-

sidade, aplicando o conceito de populações fracionárias nos diferentes estados de energia.

As equações de Bloch ópticas, um conjunto de equações diferenciais acopladas, descrevem

a evolução temporal dessas populações e dos demais elementos da matriz densidade, as

coerências entre os estados [5, 6].

Embora para alguns casos mais simples as equações de Bloch tenham solução

analítica, para outros a solução é numérica e trabalhosa. Para sistemas atômicos de dois

níveis as equações de Bloch consistem em um par de equações diferenciais acopladas. Já

para sistemas atômicos de três níveis o sistema tem seis equações diferenciais acopladas.

Abordamos ambos os casos de forma analítica e numérica neste trabalho.

A aplicação das equações de Bloch ópticas a grandes volumes de dados é de solução

numérica demorada, mesmo com uso de computadores pessoais e estações de trabalho

atuais, com processadores da geração mais recente. Conforme se discute à frente, esse

é um fator a se considerar na distruição Maxwell-Boltzmann das velocidades do vapor

atômico ou em uma ampla faixa variação de frequências incidentes.

Entretanto, cada item de tais volumes de dados considerados, sejam as velocida-

des individuais ou as frequências, são calculáveis de maneira independente. Esse fato

torna tais problemas paralelizáveis, e a aplicação de computação paralela passa a ser uma

escolha adequada para melhora do tempo de execução do programa usado para a solu-

13

ção. Soluções paralelas de processamento são alternativas de custo bastante inferior à

cara supercomputação desde os anos 1990, com os clusters e computação distribuída pela

Internet [7, 8].

Nos anos recentes, a programação de softwares para solução de problemas científi-

cos complexos tem utilizado o paralelismo em placas gráficas de vídeo (graphical processing

units - GPUs), quando aplicável. Tais dispositivos permitem ganhos significativos no de-

sempenho com um custo de aquisição e operação relativamente baixo [7, 9, 10].

Nesse contexto, tratamos neste trabalho a solução das equações de Bloch ópticads

para sistemas atômicos de dois e três níveis de um vapor atômico de rubídio em interação

com um laser de pulsos ultracurtos, utilizando a programação serializada tradicional e o

paralelismo na GPU, comparando os resultados quantitativamente, buscando estabelecer

cenários no qual a computação paralela na GPU se torna uma alternativa barata e eficiente

para problemas físicos paralelizáveis e que demandam alto desempenho ou tempo de

execução.

Iniciamos a discussão com a ambientação teórica do tema. No primeiro capítulo

apresentamos as transições atômicas e alguns efeitos relevantes da interação de átomos

com radiação. O segundo capítulo abrange um breve histórico e uma introdução ao laser

e ao laser pulsado, e a sua representação do campo elétrico.

No terceiro capítulo abordamos sistemas atômicos, especialmente átomos alcalinos,

a estrutura fina e hiperfina, o átomo de rubídio e a determinação das equações de Bloch

para sistemas atômicos de dois e três níveis do tipo cascata e do tipo Λ.

O quarto capítulo encerra a fundamentação teórica com uma breve explanação

sobre o paralelismo em GPUs e sua distinção em relação à programação serializada tra-

dicional, enquanto explana sobre as diferenças nas arquiteturas de cada modelo, antes de

demonstrar exemplos práticos de códigos equivalentes.

No quinto e último capítulo apresentamos os resultados obtidos para três diferentes

contextos, sempre com parâmetros compatíveis com vapor atômico do isótopo 85Rb em

interação com um trem de pulsos ultracurtos de laser.

Primeiramente, estudamos a dinâmica de populações para átomos de três e dois ní-

veis, com a solução numérica das equações de Bloch em cada caso, a distribuição Maxwell-

Boltzmann das velocidades no vapor atômico e a discussão dos efeitos ópticos e atômicos

envolvidos nos resultados, em conformidade com a literatura científica na área.

14

Em seguida, investigamos a solução em GPUs para a distribuição Maxwell-Boltzmann

de átomos de dois níveis, ao lado da solução serializada tradicional, com a comparação

temporal quantificada das duas soluções, visando a aplicação em problemas físicos para-

lelizáveis.

Por último, obtemos a solução na GPU de um sistema atômico de três níveis do tipo

Λ com transparência eletromagneticamente induzida, uma extensão do problema anterior

para uma situação física mais realista em um tópico de estudo mais recente.

15

2 TRANSIÇÕES ATÔMICAS

2.1 NÍVEIS DE ENERGIA

O modelo atômico de Bohr já previa que o átomo possui níveis quantizados de

energia. Como nesse modelo o elétron orbita o núcleo como em um sistema planetário

de miniatura, Bohr assumiu que apenas certas órbitas eram permitidas. O elétron assim

saltaria de uma órbita permitida para outra, apenas assim perdendo energia, emitindo

essa energia correspondente como luz em um comprimento de onda específico [6]. Os

níveis de energia do hidrogênio no modelo de Bohr são dados por sua conhecida fórmula

En =mee

4

8n2h2ε20

(2.1)

ondeme é a massa do elétron, n o chamado número quântico principal, ε0 a permissividade

do vácuo, e a carga elétrica elementar e h a constante de Planck.

O resultado de Bohr é equivalente ao da solução da equação de Schrödinger inde-

pendente do tempo para átomos de um elétron, descontadas correções como da estrutura

fina, estrutura hiperfina, efeito Zeeman e do spin do elétron [2].

2.2 INTERAÇÃO COM RADIAÇÃO

Os três processos a se considerar na interação de átomos com radiação, conside-

rando apenas transições de um fóton, são de interesse direto para este trabalho:

1. um átomo pode sair de um estado excitado para um estado de menor energia emi-

tindo um fóton, na chamada emissão espontânea;

2. um átomo pode absover um fóton e fazer a transição de um estado de menor para

um estado de maior energia, a chamada absorção;

3. átomos podem emitir fótons sob a influência de radiação, na chamada emissão esti-

mulada [2].

16

Para este trabalho, e como a abordagem usual da área, tratamos o campo de

radiação classicamente, e o sistema atômico quanticamente, já que a densidade de fó-

tons mesmo em um campo relativamente fraco pode ser aproximada como uma variável

contínua, descrita pela eletrodinâmica clássica. Essa abordagem também é chamada de

semiclássica [2, 6].

Entretanto, o vapor atômico contido em um recipiente contém, no mínimo, energia

térmica a ser considerada na interação com radiação. Tendo em vista a velocidade do

movimento dos átomos que compõe o vapor se faz necessário aplicar o efeito Doppler no

fenômeno. Se em um referencial estacionário o átomo absorve radiação na frequência ω0,

um átomo com velocidade v absorve energia quando δ = ωc − ω0 = kv. A fração de

átomos no intervalo de velocidades entre v e dv é

f(v)dv =

√M

2πkBTexp

(−Mv2

2kBT

)dv (2.2)

para um átomo de massa M na temperatura T [6]. kB é a constante de Boltzmann. Na

Figura 2.1, temos a fração de átomos em função da distribuição das velocidades para o

átomo de rubídio.

Figura 2.1: Distribuição Maxwell-Boltzmann do isótopo 85Rbpara T = 300K. O eixo vertical representa a fração de átomospara cada velocidade

17

2.3 TAXAS DE TRANSIÇÃO E REGRAS DE SELEÇÃO

Tanto para a emissão espontânea quanto para a absorção descritas na seção ante-

rior, o fóton emitido ou absorvido tem uma frequência angular ω, que pela conservação

de energia satisfaz a relação

~ω = Ej − Ei (2.3)

onde Ej é a energia do estado superior, e Ei a energia do estado menos energético [12].

O Hamiltoniano dependente do tempo que descreve a perturbação para uma interação de

dipolo elétrico com um campo ~E(t) é

H ′ = −e~r · ~E(t) (2.4)

sendo −e~r o operador de dipolo elétrico do átomo que, no caso, é representado apenas

pelo elétron que reage à interação [6, 12].

Pela regra de ouro de Fermi, a taxa de transição Wij entre os estados i e j é

proporcional ao quadrado do elemento de matriz Mij da perturbação, ou seja,

Wij =2π

~|Mij|2g(~ω), (2.5)

onde g(~ω) é a densidade de estados, isto é, o número de estados na faixa de energias de

E a E + dE. A definição do elemento de matriz é

Mij = 〈j| H ′ |i〉 . (2.6)

Considerando que a amplitude E0 do campo elétrico ~E(t) é constante no átomo

dado o pequeno tamanho do átomo em relação ao comprimento de onda da luz incidente,

e definindo o momento de dipolo elétrico µij como

µij = −e 〈j| r |i〉 , (2.7)

sendo r a componente de ~r na direção de ~E, podemos escrever concisamente o elemento

de matriz como

Mij = µijE0. (2.8)

O elemento de matriz acima leva às regras de seleção. Por tais regras, se os

18

estados não as satisfazem, a taxa de transição de dipolo elétrico será zero, e a transição

é chamada de transição proibida. Caso a transição obedeça às regras de seleção se trata

de uma transição permitida.

2.4 INTERAÇÃO COM DOIS FÓTONS

Supondo um sistema de dois níveis de energia, E1 o estado fundamental e E2 o

estado excitado, em interação com um fóton de energia

~ω =1

2(E2 − E1), (2.9)

fica evidente que tal fóton não leva à transição entre os estados. Entretanto, se dois fótons

com a mesma energia ~ω interagem com o mesmo sistema, a transição para E2 se torna

possível, desde que as regras de seleção sejam obedecidas [13].

Em outro caso possível, dois fótons de frequências diferentes, ω1 e ω2, interagem

simultaneamente com o sistema, são absorvidos e promovem a transição, ressonante em

ω1 + ω2 [14].

Ambos os casos são retratados na Figura 2.2, e envolvem a definição de um estado

virtual entre o estado fundamental e |1〉 e o estado excitado |2〉. Entretanto, tal estado

virtual não é um estado intermediário real.

Tais interações múltiplas não se limitam a dois fótons, existindo ainda interações

multifóton para três fótons ou mesmo para n fótons [15]. Para este trabalho, nos limitamos

à discussão dos casos de um e dois fótons.

Para a amplitude de probabilidade da absorção de um ou dois fótons, primeiros

definimos a frequência de Rabi [6]

Ω =µijE

~(2.10)

onde µij é o momento de dipolo da transição, mencionado na seção anterior. Assim, a

probabilidade da transição por absorção de um fóton é [15]

p1 = 2π~Ω2tg(ω) (2.11)

onde g(ω) é a densidade de estados. A probabilidade cresce linearmente com o tempo.

19

Figura 2.2: Transição do estado fundamental |1〉 para oestado excitado |2〉 após interação com dois fótons no casoa) de dois fótons de mesma frequência e b) em frequênciasdiferentes. O tracejado representa o estado virtual.

Para o caso de dois fótons,

p2 = (2π~)2Ω21Ω2

2tg(ω), (2.12)

sendo Ωi a frequência de Rabi para cada um dos campos incidentes. Para o caso de fótons

iguais, p2 ∝ Ω4 . O fator de divisão ~4 para a absorção de dois fótons mostra que tal

ocorrência é muito mais improvável que a absorção de um único fóton.

2.5 TRANSPARÊNCIA ELETROMAGNETICAMENTE INDUZIDA

A transparência eletromagneticamente induzida (electromagnetically induced trans-

parency - EIT) foi observada inicialmente por Boller et al (1991). Trata-se de um fenômeno

em que um meio opticamente opaco passa a ser transparente para a radiação na frequência

de ressonância [16].

A EIT já foi observada em sistemas atômicos e sólidos [15]. A situação ideal para

observação do fenômeno ocorre em um sistema atômico de três níveis [17, 18, 19]. Sistemas

atômicos dessa espécie são discutidos na seção 4.6, e resultados de cálculos envolvendo

EIT são discutidos na seção 6.3.

O efeito é melhor observado no caso original estudado por Boller. Nessa confi-

20

guração, um sistema atômico de três níveis, |1〉, |2〉 e |3〉 está sob ação de dois campos.

O primeiro, de frequência ω, está acoplado à transição |1〉 −→ |3〉. O segundo campo

coerente, de frequênciaω′ e mais intenso, é acoplado à transição |2〉 −→ |3〉.Nessa configuração, apresentada na Figura 2.3, e sob condições adequadas, o meio

se torna transparente para o campo de frequência ω, não havendo mais absorção [15, 16,

17, 18].

Figura 2.3: Sistema atômico de três níveis sob ação dedois campos eletromagnéticos em uma típica situação emque EIT é observada.

A EIT produzida por um trem de pulsos foi observada experimentalmente por Sau-

tenkov et al (2005), conforme previsto teoricamente [20]. Lasers pulsados são discutidos

na seção 3.2.

Estudos mais recentes mostram que na EIT produzida por um trem de pulsos as

ressonâncias para a transição de um fóton e dois fótons ocorrem simultaneamente [21].

21

3 LASERS PULSADOS

3.1 HISTÓRICO DO LASER

O termo laser é um acrônimo em inglês para amplificação da luz por emissão estimu-

lada de radiação, sendo originário do termo mais antigo maser, que significa amplificação

de micro-ondas por emissão estimulada de radiação. O maser foi proposto em 1954 por

Basov e Prokhorov e no mesmo ano por Townes. O conceito de maser é consequência da

ideia da emissão estimulada proposta por Einstein cerca de quarenta anos antes [3, 4].

O princípio do maser derivou sua versão óptica, conhecida no final dos anos 1950

como maser óptico, após o trabalho de Schawlow e Townes em 1958. Posteriormente, o

termo laser se popularizou em substituição [3].

A principal diferença entre o laser e a luz comum, característica que sua radiação

compartilha com as micro-ondas, em coesão com sua origem no maser, é que a luz dos

lasers é coerente, estando todos os fótons emitidos por seu mecanismo exatamente na

mesma fase [4, 22].

Outra propriedade importante de quase todos os lasers é a colimação, que garante

que a luz do laser fique confinada a um feixe estreito por longas distâncias, e deriva dire-

tamente do processo de construção do mecanismo do laser, que envolve diversas reflexões

e saída do mecanismo pela extremidade do tubo. Apenas fótons alinhados com o eixo do

tubo conseguem sair, já que fótons ligeiramente desalinhados colidem com as paredes do

tubo e não compoem o feixe [4].

3.2 EMISSÃO ESTIMULADA, GANHO DE LASER E INVERSÃO DE POPULAÇÃO

Se um fóton é emitido para o interior de uma cavidade contendo átomos no estado

fundamental, ele pode ser absorvido por um átomo, excitando-o para um estado de energia

mais alto. Caso encontre algum átomo já em um estado excitado de energia, sendo esse

fóton de um comprimento de onda determinado e correto, ele pode estimular o átomo a

emitir um fóton de mesmo comprimento de onda e fase, no mesmo sentido. Assim, essa

22

radiação amplificada é coerente e monocromática [4].

O ganho de laser é a medida do quão bem um meio amplifica os fótons pelo

processo descrito de emissão estimulada. Se um feixe de fótons viaja por um tubo em

uma densidade que permita serem descritos como uma onda eletromagnética, a onda

é amplificada se as emissões estimuladas superam as emissões espontâneas e as perdas

devido à saída do feixe emitido [4].

A energia do sistema de átomos obedece à aproximação clássica da distribuição de

Boltzmann, em caso de equilíbrio térmico, sendo o estado fundamental mais populoso que

os estados excitados. Entretanto, é possível bombear energia para o sistema e provocar

uma situação de desequilíbrio que viola a distruibuição, no processo chamado inversão de

população, onde um estado excitado se torna mais populoso que o estado fundamental

[3, 11].

Como um estado de não equilíbrio, as inversões de população não duram um pe-

ríodo prolongado [11]. Esse processo é necessário para o funcionamento da grande maioria

dos lasers [4].

3.3 LASER PULSADO

Lasers de onda contínua (cw, de continuous-wave) possuem um fluxo constante de

energia, enquanto lasers pulsados comprimem a saída de energia em pequenos picos, que

funcionam como pacotes espaçados de energia. A melhora desejada é na potência de pico.

Por exemplo, se 1W de saída de um laser cw for dividido em dez pulsos de 20ns cada,

a potência do pico pode ser maior que a potência média na ordem de 106, permitindo

aplicações impossíveis para um laser cw, com o mesmo gasto energético [11].

Há uma série de métodos para se produzir um laser pulsado. O mais simples

consiste no chamado Q-switching (ou chaveamento-Q), que funciona por armazenamento

de energia através de inversão de poupulação até um nível em que a energia é liberada

em um pulso único e de alta energia [11].

Há vários tipos de chaveadores-Q, e um particularmente é o do tipo E-O, que usa

um cristal eletro-óptico, chamado célula Pockels, que polariza a luz com uma diferença

de 90o dependendo da voltagem aplicada [11].

23

Em uma adaptação do Q-switching o método de cavity dumping também permite

produzir um laser pulsado, com o uso combinado de um chaveador E-O, pois a alternância

da polarização da luz permite que o laser produza um pulso de alta energia e depois cesse

até novo estímulo [4].

Contudo, para produção dos pulsos ultracurtos abordados nesta monografia a téc-

nica utilizada é o modelocking, que, no domínio do tempo, consiste em um pulso curto

refletido continuamente por espelhos na cavidade. Cada vez que o pulso encontra o espe-

lho parcialmente transmissor um pulso é gerado. A energia é compactada no pulso por

um modulador que pode ser, por exemplo, um chaveador E-O que "abre"uma vez a cada

viagem completa [4, 11].

No domínio da frequência, os diferentes modos longitudinais do laser com suas

pequenas diferenças de frequência oscilam em fase na cavidade do laser. No laser mode-

locked, os modos têm suas fases relativamente associadas e travadas (locked), formando

um pulso que viaja pela cavidade, com pico de energia no ponto onde todos os modos

interferem construtivamente, pois todos os modos recebem a mesma amplificação com a

abertura do chaveamento [4].

3.3.1 Representação do campo elétrico

Uma discussão completa do cálculo do campo elétrico complexo do trem de pul-

sos ultracurtos se encontra em Diels e Rudolph (2006) [23]. Para representar os pulsos

ultracurtos a intervalos constantes, temos que E(t) é dado por [24]

E(t) =N−1∑

n=0

E0(t− nTR)e−i(ωct−nωcTR+n∆φ) (3.1)

onde E0 é uma função que representa a envoltória do pulso, N é a quantidade de pulsos,

ωc é a frequência da onda e ∆φ a diferença de fase pulso-a-pulso. A Figura 3.1 mostra

uma representação gráfica do trem de pulsos com uma escolha arbitrária de parâmetros

para melhor visualização. No problema real em análise, os pulsos têm duração da ordem

de 10−13s, enquanto o tempo entre os pulsos dura 10−8s, o que torna pouco prática a

visualização gráfica trem de pulsos.

Para uma representação realista de E0(t) nos cálculos, podemos representar o pulso

24

Figura 3.1: Representação do campo elétrico para um trem de pulsos. A curva vermelhaé a envoltória dos pulsos.

como uma curva secante hiperbólica na seguinte forma [23]

E0(t) = E0sech

(1,76t

Tp

), (3.2)

onde E0 é a amplitude do campo, Tp é a largura temporal do pulso e a constante 1,76

é uma escolha conveniente para a forma do pulso. Utilizamos essa representação nos

cálculos deste trabalho.

A Figura 3.2 mostra ilustrativamente um pulso de largura temporal 100 fs e a

Figura 3.3 sua transformada de Fourier. O pulso, no domínio da frequência, tem largura

de 5 THz.

25

Figura 3.2: Ilustração de um pulso com envoltória e largura de100 fs.

Figura 3.3: Transformada de Fourier do pulso.

26

4 SISTEMAS ATÔMICOS

No início do século XX já estava estabelecido que o átomo continha elétrons, que

eram em si muito mais leves que o átomo, e que átomos podiam ganhar ou perder elétrons,

afetando a sua carga. Após experimentos de Geiger, Marsden e Rutherford, este último

propôs em 1911 um modelo onde quase toda a massa do átomo estava concentrada em

um pequeno e denso núcleo [2].

Também já era amplamente sabido que qualquer elemento emitia um espectro

luminoso característico, e também que tal espectro era composto por linhas discretas

de emissão, e que os elementos também tinham linhas definidas de absorção. As linhas

de emissão do espectro do hidrogênio eram notórias, organizadas em séries regulares em

várias faixas do espectro eletromagnético [1, 2, 6].

O modelo de Bohr para o átomo de hidrogênio, proposto em 1913, que expandia a

ideia de Rutherford de elétrons orbitando o núcleo como um minúsculo sistema planetário

para um cenário em que apenas algumas órbitas eram permitidas, efetivamente quantizou

níveis de energia e deu conta do espectro discreto do hidrogênio [6].

Embora o modelo orbital fosse útil para explicar as linhas de emissão e absorção

do hidrogênio e alguns outros efeitos naturais [2], mesmo após correções relativísticas de

Sommerfeld a ideia foi superada pelas funções de onda e pelas soluções da equação de

Schrödinger, que ainda permitiu eliminar as distorções do modelo de Bohr-Sommerfeld

para átomos com mais de um elétron [6].

4.1 ÁTOMOS ALCALINOS

Os elétrons de um átomo no estado fundamental se distribuem de uma forma

que minimiza a energia do sistema, não se agrupando todos na camada mais baixa onde

n = 1 devido ao princípio da exclusão de Pauli, que restringe o número de elétrons em

uma dada camada ao estabelecer que dois elétrons não podem ter o mesmo conjunto de

números quânticos. De forma equivalente, podemos dizer que os elétrons se disttribuem

nas camadas obedecendo à distribuição de Fermi-Dirac, uma vez que são férmions, isto é,

partículas de spin semi inteiro [6].

27

Assim, elétrons preenchem as camadas progressivamente conforme o número atô-

mico Z cresce, sendo que para Z = 2, 10, 18, 36... as camadas são completas, formando

os chamados gases nobres (He, Ne, Ar, Kr, ...). Os átomos alcalinos (Li, Na, K, Rb,

...) consistem em um átomo de gás nobre como núcleo mais um elétron na camada mais

externa.

Tabela 4.1: Configuração das camadas eletrônicas emátomos alcalinos.

Elemento Distribuição de elétronsLítio 1s22sSódio 1s22s2p63sPotássio 1s22s2p63s23p64sRubídio 1s22s2p63s23p63d104s24p65sCésio 1s22s2p63s23p63d104s24p64d105s25p66s

Nesse caso, como se vê na Tabela 4.1, o elétron da camada mais externa para

átomos alcalinos mais pesados não está necessariamente na camada subsequente. Podemos

observar tal fato a partir do potássio, onde a camada 4s é preenchida antes da 3d. Isso

se deve aos efeitos de penetração, isto é, o quanto a camada externa "enxerga"a carga

nuclear no núcleo atômico, e blindagem, mais efetiva nas camadas nd que nas camadas

ns, conforme a expressão [2, 6]

E(n, l) = −hc R∞(n− δl)2

, (4.1)

que é uma versão da fórmula correspondente do modelo atômico de Bohr que funciona

especialmente bem para os níveis de energia dos átomos alcalinos. Na expressão, R∞ é a

constante de Rydberg e l o número quântico secundário. O termo δl é chamado defeito

quântico, e é maior para a camada s que para a camada d, levando ao efeito discutido [6].

Átomos alcalinos são de especial interesse por sua energia de ionização. Esta

atinge máximos nos átomos de gases nobres, e mínimos nos átomos alcalinos, conforme

visto na Figura 4.1. Além disso, os estados excitados dos alcalinos podem ser expressos

integralmente pela descrição de seu elétron mais externo, o que torna particularmente

simples a sua análise de espectro óptico em termo de seus estados excitados [1, 2].

28

Figura 4.1: Energia de ionização em função do número atômico Z. Comdados da Tabela Periódica dos Elementos, baseado na figura de Bransdene Joachain [2, p. 305].

4.2 ESTRUTURA FINA E HIPERFINA

A estrutura fina surge de efeitos relativísticos que levam a pequenas divisões nos

níveis de energia do átomo. O método mais comum para cálculo da estrutura fina é

utilizando a teoria de perturbações, o que requer o conceito de spin do elétron e o da

interação spin-órbita [2, 6].

Para a determinação da estrutura fina, iniciamos pela definição do momento an-

gular eletrônico total ~J , que é a soma entre o momento angular orbital ~L e o spin ~S

[6, 12]~J = ~L+ ~S. (4.2)

Para cada configuração eletrônica dos elétrons de valência há uma série de estados

definidos por L, S e J . Os estados LS são chamados termos atômicos, e uma combinação

de J e seus diferentes termos relativos a L e S são chamados níveis, e permitem definir a

notação espectroscópica [12]:

|L, S, J〉 ≡(2S+1) Lj (4.3)

Da Equação 4.2 podemos fazer

~J2 = (~L+ ~S)2

~J2 = ~L2 + 2〈~L · ~S〉+ ~S2

〈~L · ~S〉 =1

2〈 ~J2 − ~L2 − ~S2〉

29

〈~L · ~S〉 |LSJ〉 =~2

2[J(J + 1)− L(L+ 1)− S(S + 1)] |LSJ〉 (4.5)

Como o Hamiltoniano da interação spin-órbita é dado por [12]

Hso = α~L · ~S (4.6)

onde α é uma constante, e a variação de energia devido à interação spin-órbita é o valor

esperado desse Hamiltoniano, em conjunto com a Equação 4.5 tem-se que

Eso = β[J(J + 1)− L(L+ 1)− S(S + 1)] (4.7)

onde β é uma constante. Essa equação indica que para diferentes termos J obtidos pelos

mesmos valores de L e S têm diferentes energias.

Para a estrutura hiperfina se considera o efeito do momento angular total do átomo~F , dado por

~F = ~J + ~I (4.8)

onde ~I é o spin nuclear. O Hamiltoniano da estrutura hiperfina é dado por [6]

HEHF = A~J · ~I (4.9)

onde A é o coeficiente A de Einstein. Logo, variação de energia da estrutura hiperfina é

EEHF = A〈 ~J · ~I〉. (4.10)

Seguindo um procedimento similar ao que conduziu à Equação 4.5 para o termo 〈 ~J · ~I〉,

EEHF = A~2

2[(F + 1)− J(J + 1)− I(I + 1)] (4.11)

A Figura 4.2 apresenta as estruturas fina e hiperfina do rubídio, elemento utilizado

nesta monografia. Para átomos alcalinos, as transições hiperfinas n2S1/2 → n2P1/2 são

as transições D1 e n2S1/2 → n2P3/2 são as transições D2. A absorção e emissão nas

proximidades dessas chamadas linhas D é de interesse especial em espectroscopia e em

física atômica [25].

30

Figura 4.2: Estruturas fina e hiperfina do rubídio.

4.3 O ÁTOMO DE RUBÍDIO

As soluções e dados neste trabalho são compatíveis com vapor atômico de rubídio

(Rb). O Rb é um metal alcalino altamente reativo que ocorre naturalmente em uma

mistura do isótopo 85Rb com o levemente radioativo 87Rb, em minerais de onde também

se extrai outros metais alcalinos como o césio. O 85Rb é o único isótopo estável do

rubídio, o mais abundante naturalmente e cujos parâmetros foram considerados. Possui

37 elétrons, apenas um na última camada, uma massa atômica de 84,911789738u e spin

nuclear 5/2 [26].

Metais alcalinos como o rubídio são muito usados em estudos envolvendo espec-

troscopia por motivos que os tornam uma escolha bastante óbvia na área: o espectro

de absorção é simples, bastante estudado, bem definido e conhecido. Além disso, sua

estrutura simples, com apenas um elétron de valência, permite uma modelagem teórica

detalhada [27].

As linhas D são facilmente alcançáveis na região do infravermelho por lasers de

Ti:safira, cujos parâmetros são adotados nos cálculos adiante [28].

31

4.4 AS EQUAÇÕES DE BLOCH ÓPTICAS

Para um átomo interagindo com um campo eletromagnético se assume que o Ha-

miltoniano tem a forma

H = H0 + V (t) (4.12)

onde H0 é o Hamiltoniano do átomo livre e V (t) é a energia da interação do átomo com

o campo, dada no caso pela aproximação de dipolo elétrico V (t) = −µE(t), considerando

apenas a componente na direção do campo. Logo, o Hamiltoniano se torna

H =N∑

k=1

~ωk |k〉 〈k| − µE(t) (4.13)

sendo ~ωk a energia do estado quântico representado por k. Para a Equação 4.13 usamos

a definição do Hamiltoniano do átomo livre H0 [29]. Assim, adotamos como base os

autoestados de H0, que são bem conhecidos pela solução da equação de Schrödinger.

A matriz densidade se compõe das populações fracionárias dos estados atômicos,

e sua evolução temporal é dada pela equação de Liouville-Neumann [5].

∂ρ

∂t= − i

~[H, ρ] (4.14)

onde ρ é o operador matriz densidade e H é o Hamiltoniano total do sistema. É necessário

considerar ainda na Equação 4.14 os fenomenológicos termos de relaxação dos estados

excitados [15, 29, 30], que chamaremos γij. Assim, a Equação 4.14 para um dado elemento

ij da matriz densidade se torna

ρij = − i~

[H, ρ]ij − γijρij (4.15)

4.5 SISTEMA DE DOIS NÍVEIS

A matriz densidade ρ para um sistema de dois níveis é dada por [6]

ρ = |α〉 〈α| =

c1

c2

[c∗1 c∗2] =

|c1|2 c1c

∗2

c2c∗1 |c2|2

=

ρ11 ρ12

ρ21 ρ22

(4.16)

32

onde ρii são as chamadas populações fracionárias [5, 6], ρij para i 6= j as coerências

representativas da resposta do sistema a uma dada frequência [6] e ck é a amplitude da

função de onda do estado k [12].

Para calcular os elementos ρij da matriz densidade, parte-se da Equação 4.15,

omitindo-se a princípio o termo de relaxação por simplicidade. Assim, por exemplo, para

termo ρ11,

∂t〈1| ρ |1〉 = − i

~〈1| [H, ρ] |1〉

ρ11 = − i~〈1| Hρ− ρH |1〉

ρ11 = − i~

(〈1| Hρ |1〉 − 〈1| ρH |1〉

)

ρ11 = − i~

2∑

k=1

(〈1| H |k〉 〈k| ρ |1〉 − 〈1| ρ |k〉 〈k| H |1〉

)

ρ11 = − i~

2∑

k=1

(〈1| ~ωk |k〉 〈k| − µE |k〉 〈k| ρ |1〉 − 〈1| ρ |k〉 〈k| ~ωk |k〉 〈k| − µE |k〉 |1〉) .

Como µij é o momento de dipolo elétrico da transição |i〉 −→ |j〉, na forma matricial

escrevemos

µ.=

0 µ12

µ12 0

(4.18)

e ρ11 se torna

ρ11 = − i~

(~ω1ρ11 − µ12Eρ21 − ~ω1ρ11 + µ21Eρ13) (4.19a)

ρ11 = iµ12E

~ρ21 − i

µ21E

~ρ12. (4.19b)

A frequência de Rabi Ωij é dada por [6, 30]

Ωij =µijE

~. (4.20)

Portanto, o elemento da matriz densidade ρ11 para um sistema atômico de dois níveis é

dado por

ρ11 = iΩ21ρ21 + c.c.+ γ22ρ22 (4.21)

ao incluirmos novamente o termo de relaxação. O cálculo dos elementos restantes das

33

matriz densidade é semelhante, e pode ser generalizado para os demais termos:

ρ11 = iΩ21(t)ρ21 + c.c.+ γ22ρ22 (4.22a)

ρ22 = iΩ12(t)ρ12 + c.c.− γ22ρ22 (4.22b)

ρ12 = [i(ω2 − ω1)− γ12]ρ12 − iΩ12(t)(1− 2ρ22) (4.22c)

Para simplificar essa representação, utilizamos os seguintes fatos. Uma das pro-

priedades da matriz densidade é que Tr(ρ) = 1 [5], isto é, para um sistema de dois níveis

ρ11 + ρ22 = 1. Também, ρij = ρ∗ji e Ω12 = Ω∗21 ≡ Ω. Definimos ainda ωj − ωi = ωji e

ω21 − ωc = δ, a dessintonia do campo com respeito à ressonância atômica.

Em adição, definimos a variável σij, aplicando a aproximação de onda girante em

extensão ao formalismo da matriz densidade:

σij = ρije−iωct (4.23)

em uma alteração que não afeta as populações fracionárias (quando i = j), mas altera a

representação das coerências [6, 31].

Desta forma, obtemos as equações de Bloch ópticas para um sistema atômico de

dois níveis.

ρ22 = iΩ0(t)σ12 + c.c.− γ22ρ22 (4.24a)

σ12 = (iδ − γ12)σ12 + iΩ0(t)(2ρ22 − 1) (4.24b)

Neste trabalho os cálculos envolvendo sistemas atômicos de dois níveis utilizam as

Equações 4.24.

34

4.6 SISTEMA DE TRÊS NÍVEIS

As equações de Bloch para um sistema atômico de três níveis se definem pelo mesmo

método da seção anterior, com as mesmas definições e aproximações, quando aplicáveis.

O operador de dipolo elétrico µ assume a forma

µ.=

0 µ12 µ13

µ21 0 µ23

µ31 µ32 0

(4.25)

Entretanto, consideramos neste trabalho dois tipos de sistemas atômicos de três

níveis, o tipo Λ e o tipo cascata, discutidos a seguir.

4.6.1 Tipo Λ

Uma representação do sistema tipo Λ é mostrada na Figura 4.3. O estado |3〉 é o

de maior energia. Há duas frequências, ω1 e ω2, para as transições entre |1〉 e |3〉 e entre

|2〉 e |3〉. A transição entre |1〉 e |2〉 é proibida por dipolo elétrico [32].

Figura 4.3: Representação de um sistemaatômico de três níveis do tipo Λ.

Após cálculos semelhantes ao realizado para um sistema de dois níveis, temos as

seguintes equações para os termos da matriz densidade de um sistema de três níveis do

35

tipo Λ.

ρ11 = iΩ31(t)ρ31 + c.c.− γ11ρ33 (4.26a)

ρ22 = iΩ23(t)ρ32 + c.c.− γ22ρ33 (4.26b)

ρ22 = (iΩ31(t)ρ13 + c.c.) + (iΩ32(t)ρ23 + c.c.)− γ33ρ33 (4.26c)

ρ12 = (iω21 − γ12)ρ12 + iΩ13ρ32 − iΩ32ρ13 (4.26d)

ρ13 = (iω31 − γ13)ρ13 + iΩ13(ρ33 − ρ11)− iΩ23ρ12 (4.26e)

ρ23 = (iω32 − γ23)ρ23 + iΩ13(ρ33 − ρ22)− iΩ13ρ21 (4.26f)

Consideramos iguais as frequências de Rabi das duas transições, isto é, Ω31(t) =

Ω23(t) ≡ Ω(t). As taxas de relaxação do estado excitado |3〉 para os estados fundamentais

|1〉 e |2〉 também são tratadas como iguais e γ13 = γ23 ≡ γ, e γ33 = 2γ. Como a transição

|1〉 −→ |2〉 é proibida, γ12 = 0.

Usando as aproximações para os termos σij, adotamos a seguinte notação

ρ12 = σ12ei(ω1−ω2)t

ρ13 = σ13eiωct)

ρ23 = σ23eiωct)

δk = ω3k − ωk

e chegamos às equações de Bloch para um sistema de três níveis Λ adotadas nos cálculos

deste trabalho.

ρ11 = −iΩ(t)σ13 + c.c.− γρ33 (4.28a)

ρ22 = −iΩ(t)σ23 + c.c.− γρ33 (4.28b)

ρ22 = (iΩ(t)σ13 + c.c.) + (iΩ(t)σ23 + c.c.)− 2γρ33 (4.28c)

σ12 = i(δ2 − δ1)σ12 − iΩ(t)σ23 − iΩ(t)σ13 (4.28d)

σ13 = (iδ1 − γ)σ13 + iΩ(t)(ρ33 − ρ11 − σ12) (4.28e)

σ23 = (iδ2 − γ)σ23 + iΩ(t)(ρ33 − ρ22 + σ12) (4.28f)

36

4.6.2 Tipo cascata

Se um dos três estados tem uma energia intermediária entre os outros dois, a

configuração é chamada sistema em cascata, ou escada. Na Figura 4.4 apresentamos um

sistema com essa estrutura, sendo |2〉 o estado intermediário [32].

Figura 4.4: Represen-tação de um sistema atô-mico de três níveis tipocascata.

Os termos da matriz densidade são assim dados por

ρ11 = −iΩ21(t)ρ12 + c.c.+ γ22ρ22 (4.29a)

ρ21 = iΩ21(t)ρ12 − iΩ32(t)ρ23 + c.c.− γ22ρ22 + γ33ρ33 (4.29b)

ρ33 = iΩ32(t)ρ23 + c.c.− γ33ρ33 (4.29c)

ρ12 = (iω21 − γ12)ρ12 − iΩ32(t)ρ13 + iΩ12(t)(ρ22 − ρ11) (4.29d)

ρ23 = (iω32 − γ23)ρ23 − iΩ21(t)ρ13 + iΩ32(t)(ρ33 − ρ22) (4.29e)

ρ13 = i(ω31 − γ13)ρ13 − iΩ023(t)ρ12 + iΩ12(t)ρ23. (4.29f)

Por procedimentos similares aos casos anteriores, chegamos às equações de Bloch

37

para o caso, dadas por

ρ11 = −iΩ21(t)σ12 + c.c.+ γ22ρ22 (4.30a)

ρ21 = iΩ21(t)σ12 − iΩ32(t)σ23 + c.c.− γ22ρ22 + γ33ρ33 (4.30b)

ρ33 = iΩ32(t)σ23 + c.c.− γ33ρ33 (4.30c)

σ12 = [i(δ12 −∆12)− γ12]σ12 − iΩ32(t)σ13 + iΩ12(t)(ρ22 − ρ11) (4.30d)

σ23 = [i(δ23 −∆23)− γ23)]σ23 − iΩ21(t)σ13 + iΩ32(t)(ρ33 − ρ22) (4.30e)

σ13 = [i(δ12 + δ23 −∆12 −∆23)− γ13]σ13 − iΩ023(t)σ12 + iΩ0

12(t)σ23 (4.30f)

sendo δij a dessintonia do campo e ∆ij o deslocamento Doppler para a transição i −→ j.

∆ij é dado por

∆ = kv (4.31)

sendo v a velocidade de um grupo de átomos e k o número de onda, dado por k = 2π/λ,

onde λ é o comprimento de onda do laser.

38

5 PARALELISMO EM UNIDADES DE PROCESSAMENTO GRÁFICO

A popularização dos computadores pessoais para uso cotidiano nos ambientes do-

mésticos ou de trabalho se deu através de microcomputadores, máquinas baseadas no

funcionamento de um microprocessador único chamado unidade central de processamento

(do inglês central processing unit, CPU) [33].

Em paralelo, embora com muitos pontos de contato e evolução compartilhada,

se desenvolve o campo da supercomputação, que visa resolver problemas que demandam

alto poder computacional através dos chamados supercomputadores. Ainda com o mesmo

propósito, mas aproveitando máquinas de arquiteturas diversas interligadas por redes de

computadores, tem-se a computação multinó, cujo principal exemplo é o cluster [7].

A tendência atual da computação de alto desempenho é pelo processamento para-

lelo. Mesmo as CPUs atuais para uso doméstico seguem evoluindo em número de núcleos

paralelos. Como desenvolvimento relativamente recente, há o uso de placas gráficas como

alternativa para computação paralela. Um dos principais motivos é a barreira dos 4 GHz

de frequência de processamento para núcleos de CPU, um limite onde a tecnologia atual

produz muito calor e consome muita energia, tornando a solução cara pelos custos de

resfriamento e de eletricidade [7].

5.1 PROGRAMAÇÃO SERIALIZADA

A maioria das CPUs atuais segue a arquitetura de von Neumann, e executa pro-

gramas através do ciclo de máquina que envolve buscar instruções na memória principal,

interpretá-las e executá-las [7, 34]. Trata-se de um processo simples, mas cada núcleo de

CPU só pode lidar com um ciclo de máquina por vez.

5.1.1 Arquitetura da CPU

A CPU busca suas instruções na memória principal da máquina, mas ao invés de

buscar uma instrução por vez e a executar de imediato, pode buscar blocos de instruções

39

e as armazenar em estruturas de memória chamadas cache. Na chamada hierarquia de

memória, caches se situam acima da memória principal, geralmente integradas ao próprio

processador. Muitas vezes há dois níveis de cache, o mais inferior compartilhado pelos

núcleos da CPU e o superior vinculado a cada núcleo [7].

Na arquitetura das CPUs abordadas neste trabalho, todas Intel x86, pode haver

dois níveis de cache, chamados L1 e L2, por ordem de precedência na hierarquia. Ou-

tras CPUs mais avançadas podem ter ainda outro nível de cache compartilhado entre

os núcleos, chamado L3. A Figura 5.1 apresenta um esquema simplificado da arquite-

tura da CPU para um processador moderno de quatro núcleos, considerando núcleos de

processamento e hierarquia de memória.

Figura 5.1: Estrutura simplificada da hierarquia de memória e processamento deuma CPU atual. Processadores de baixo custo podem ter menos níveis de cache. A ca-pacidade de processar dados é maior com a proximidade do núcleo de processamento,e a capacidade de armazenamento cresce no sentido oposto.

5.2 PROGRAMAÇÃO PARALELA

Com os custos crescentes dos computadores, alternativas paralelas de computação

já eram populares nos anos 1990 com a solução multinó dos clusters, máquinas comuns

interligadas em rede responsáveis cada uma por um bloco de processamento. Um conceito

simples que foi adaptado a níveis de microprocessadores e placas gráficas multinúcleo [7].

A Figura 5.2 mostra um cluster esquematizado.

40

Figura 5.2: Estrutura simplificada de um cluster de computadorespara processamento paralelo.

5.3 PARALELISMO EM PLACAS GRÁFICAS

A programação paralela na GPU exige um entendimento maior do funcionamento

do hardware para aproveitamento melhor do alto desempenho, em contraste com a pro-

gramação tradicional de mesmo nível na CPU [7].

GPUs surgiram no contexto de processamento de gráficos em três dimensões em

ambiente computacional, especialmente para jogos que utilizavam engines 3D [35]. O alto

poder de processamento das GPUs, entretanto, em conjunto com otimização de bibliotecas

de softwares específicas, é usado atualmente em diversas soluções científicas e técnicas de

problemas que demandam desempenho, em diversas áreas do conhecimento, como Física,

Computação, Biologia e Medicina [8].

Em problemas físicos, computação na GPU tem sido usada em diversas áreas como

simulações de Monte Carlo do modelo de Ising [9], simulações de modelos de spin [10],

óptica não-linear [36] e simulações de colisões [37].

41

5.3.1 Arquitetura da GPU

A seção de interesse na arquitetura de uma GPU envolve os streaming multipro-

cessors (SM), ou multiprocessadores de fluxo, unidades de processamento responsáveis

pela execução de códigos em paralelo. A GPU também tem sua hierarquia de memória

própria, e se comunica com a CPU através de uma interface por onde se troca dados nos

dois sentidos [7].

O esquema básico dessa estrutura está na Figura 5.3. A interface entre a GPU e a

CPU funciona numa frequência menor que a capacidade das duas pontas, funcionando, no

termo computacional aplicado ao caso, como um gargalo, sendo um importante fator a se

considerar na escolha da solução computacional a se utilizar. Em alto nível de abstração,

definimos uma função a ser executada na GPU, chamada kernel. Invocamos o kernel

paralelamente através de um grid de até três dimensões de blocos de execução. Cada

bloco possui uma estrutura de até três dimensões de threads. Cada bloco é associado

a um multiprocessador, que executa as threads daquele bloco, como esquematizado na

Figura 5.4 [38].

Figura 5.3: Esquema simplificado de uma GPU atual, com hiera-quia de memória dos SMs e interface com a CPU.

42

Figura 5.4: Esquema simplificado da distribuição de blocos por multiprocessador deuma GPU.

5.3.2 Programação paralela em CUDA-C

Em um típico código serializado, para a solução das equações de Bloch consi-

derando a distribuição Maxwell-Boltzmann das velocidades, adotaríamos uma solução

semelhante à seguinte:

1 (...)

2

3 #define GAMMA_22 2*M_PI*5e6

4 #define OMEGA_0 GAMMA_22 *0.1

5 #define LAMBDA1 780e-9

6

7 (...)

8

9 for (v = -600; v < 600; v += 0.001)

10 delta1 = ((2* M_PI)/LAMBDA1)*v;

11 rho22 = RK4(delta1 , OMEGA_0);

12

13 (...)

14

43

Em tal exemplo, o laço de repetição executa sequencialmente 1,2×106 vezes o có-

digo que integra as equações de Bloch, contido na função RK4(). Os termos em maiúsculas

são constantes. Para a paralelização na GPU, primeiramente definimos um kernel que

será executado paralelamente.

1 __global__ void kdmb(float *d_rho22 , float *d_vel)

2 int idx = threadIdx.x + blockIdx.x * blockDim.x;

3 float delta = ((2 * PI) / LAMBDA1)*(d_vel[idx]);

4

5 (...)

6

7 d_rho22[idx] = cuCrealf(rho_22)*exp(-U*U*d_vel[idx]*d_vel[

idx]);

8

A primeira linha abaixo da declaração do método kmdb() define um índice baseado

no número de blocos e threads definidos antes da execução. Após definir as variáveis já

reservando o espaço em memória necessário e antes de invocar o kernel, devemos copiar

os dados da memória principal do computador para a memória da GPU. Para tanto,

utilizamos a função cudaMemcpy() com a opção cudaMemcpyHostToDevice, que nessa

configuração faz a cópia dos dados das variáveis definidas no sistema anfitrição para a

GPU.

É necessário uma variável para uso no sistema anfitrião, por convenção definida

com o prefixo h_ de host, e outra para a GPU com o prefixo d_, de device.

1

2 #define MINV -600

3 #define MAXV 600

4 #define PASSO 0.01

5

6 (...)

7

8 const float ARRAY_SIZE = (MAXV - MINV)/PASSO;

9

10 int main(int argc , char *argv [])

11 (...)

44

12 int size = (ARRAY_SIZE)*sizeof(float);

13 float *h_rho22 = (float*) malloc(size);

14 float *d_rho22;

15 float *h_vel = (float*) malloc(size);

16 float *d_vel;

17

18 (...)

19

20 cudaMemcpy(d_rho22 , h_rho22 , size , cudaMemcpyHostToDevice);

21 cudaMemcpy(d_vel , h_vel , size , cudaMemcpyHostToDevice);

22

23 (...)

24

25

Tal processo leva tempo dependente da frequência de operação do hardware host, e

o trânsito no sentido inverso para tratamento adequado dos dados se dará após os cálculos,

o que deve ser considerado na escolha pela paralelização [8]. Detalhes dessa característica

são discutidos de maneira quantitativa na seção 6.2.

A invocação do kernel procede à execução em paralelo, de acordo com a arquitetura

da GPU, e segue o seguinte padrão.

1 (...)

2 dim3 grid(50, 100);

3

4 (...)

5 kdmb <<<grid , 256>>>(d_rho22 , d_vel);

6 (...)

Nesse exemplo de execuções em blocos de três dimensões, um grid de 5000 conjun-

tos bidimensionais de 256 threads é invocado para execução na GPU. Apesar da abstração

do paralelismo invocar todas as 1,28×106 threads ao mesmo tempo, elas não serão execu-

tadas em sua totalidade de maneira simultânea, estando sujeitas às limitações de memória

nos devidos graus de hierarquia e do número de SMs de cada hardware.

Após a invocação do kernel e execução dos dados em paralelo na GPU, os dados

precisam ser deslocados de volta para a memória principal do computador para o trata-

45

mento de saída dos dados em tela ou arquivo, novamente usando a função cudaMemcpy(),

desta vez com a opção cudaMemcpyDeviceToHost:

1 (...)

2 cudaMemcpy(h_rho22 , d_rho22 , size , cudaMemcpyDeviceToHost);

3

4 for (i = 0; i < ARRAY_SIZE; i++)

5 (...)

6

7 (...)

46

6 RESULTADOS

6.1 DINÂMICA DE POPULAÇÕES EM ÁTOMOS DE TRÊS NÍVEIS EM CASCATA

Para a solução das equações de Bloch, tanto para o sistema de dois níveis quanto

para o sistema de três níveis, aplicamos o método Runge-Kutta de 4a ordem [39], utili-

zando programas desenvolvidos em linguagem C (Apêndices 1 e 2). Os códigos C foram

compilados em ambiente Linux Mint 17, com gcc 4.8.2, em um computador com pro-

cessador Intel Core i5. Realizamos todos os cálculos desta seção na CPU, sem uso de

paralelismo, estudado nas seções seguintes.

Em todos os resultados apresentados a seguir consideramos um trem de pulsos de

largura temporal Tp = 100fs, e um intervalo de tempo entre pulsos consecutivos TR =

10ns, valores que representam parâmetros típicos para um laser comercial de Ti:safira

pulsado. A Figura 6.1 traz os gráficos da população ρ22 de um sistema de átomos de dois

níveis, alterando os valores da frequência de Rabi Ω0.

0123

ρ22×

104

Ω0 = γ22/100

0123

ρ22×

102

Ω0 = γ22/10

0 100 200 300 4000246

t(ns)

ρ22×

10

Ω0 = γ22

0 100 200 300 4000246

t(ns)

ρ22×

10

Ω0 = 10γ22

Figura 6.1: População ρ22 em função do tempo, com variações de Ω0. Utilizados como parâmetrosγ22 = 2π × 5MHz, δ = 0, γ12 = γ22/2, valores realistas para a transição 5S → 5P do rubídio.

Os picos na figura indicam a ação do pulso do laser, que excita os átomos, aumen-

tando a população fracionária ρ22. Os picos seguintes acontecem antes do tempo total de

decaimento, aumentando o valor de ρ22 progressivamente até o equilíbrio, que ocorre por

volta de t = 200ns.

47

Notamos que quando a frequência de Rabi é uma fração da taxa de relaxação do

estado excitado, a evolução da excitação segue de maneira semelhante, apesar da diferença

na ordem de grandeza da população ρ22. Quando, por outro lado, Ω0 é igual ou maior

que γ22, o equilíbrio de ρ22 ainda ocorre próximo de t = 200ns, após decair de um valor

máximo atingido anteriormente.

Além disso, para campos muito intensos, como no caso em que Ω0 = 10γ22, perce-

bemos uma oscilação no valor médio de ρ22, as chamadas oscilações de Rabi, que ocorrem

também na excitação de átomos por lasers contínuos, e se devem ao fato de laser ora ex-

citar os átomos do estado 1 para o estado 2 (absorção) e ora no sentido inverso (emissão

estimulada), alternadamente, em uma frequência igual a Ω/2π [12].

A figura 6.2 apresenta os gráficos da população ρ22 também em um sistema de

átomos de dois níveis, desta vez com variações da dessintonia de campo.

01234

ρ22×

102

δ = 0

0123

ρ22×

103

δ = γ22

0 100 200 300 40001234

t(ns)

ρ22×

103 δ = 2γ22

0 100 200 300 4000123

t(ns)

ρ22×

102

δ = 2πfr

Figura 6.2: População ρ22 em função do tempo, com variações de δ. Faz-se γ22 = 2π × 5Mhz,δ = 0, γ12 = γ22/2 e fr = 100MHz.

Com a definição para a taxa de repetição fr ≡ 1/TR, observamos que quando

δ = 2πfr, a evolução temporal de ρ22 é semelhante à de quando δ = 0. Isso acontece pois

o espectro de um trem de pulsos consiste em um pente de frequências, isto é, um conjunto

de milhares ou milhões de modos discretos de frequência separados por fr. Assim, sempre

que δ = 2πmfr, onde n é um número inteiro, os átomos estarão em ressonância com o

modo m do pente, e portanto serão excitados. Para os demais valores de δ, observamos a

alternância entre interferência destrutiva e construtiva antes do equilíbrio, e a excitação

de uma fração bem menor da população de átomos.

48

A seguir, a Figura 6.3 mostra o resultado alcançado para as populações ρ22 e ρ33

de um sistema atômico de três níveis em cascata, novamente variando Ω0 e δ.

0123

ρ22×

104

Ω0 = γ22/100

0

1

2

ρ33×

104

Ω0 = γ22/10

0246

ρ22×

10

Ω0 = 10γ220

2

4

ρ33×

102

Ω0 = 10γ22

0123

ρ22×

103

δ = γ22

0

2

33×

109

δ = γ22

0 100 200 300 4000123

t(ns)

ρ22×

102

δ = 2πfr

0 100 200 300 4000

1

t(ns)

ρ33×

104

δ = 2πfr

Figura 6.3: Variação temporal das populações ρ22 e ρ33. Nas duas primeiras linhas de figurasδ = 0 enquanto variamos a frequência de Rabi. Nas seguintes variamos a dessintonia de campoenquanto Ω0 = γ22/10.

Após, distribuimos as populações de um sistema atômico de três níveis em função

da velocidade. Fazendo ∆ = kv, onde k = 2π/λ, atribui-se λ = 780nm, e se resolve

numericamente as equações e Bloch. Multiplica-se então os valores das populações ρ22 e

ρ33 após t = 400ns pela fração populacional na Equação 2.2.

A Figura 6.4 mostra os resultados para ρ22 e ρ33. Observamos que apenas alguns

grupos de átomos em determinadas velocidades são excitados. Conforme notado por

Aumiller (2009) [40], as populações acompanham a distribuição por velocidade da fração

populacional dos átomos, que apresentamos para o átomo de rubídio na Figura 2.1. A

forma de pente da distribuição se deve à excitação por trem de pulsos.

A estrutura de picos é característica de interferência construtiva. Os picos duplos

49

da Figura 6.4b se devem à alternância entre uma condição de interferência construtiva e

uma de interferência destrutiva. Para o caso da interferência destrutiva, uma vez que a

transição dos estados ocorre em determinado comprimento de onda, o acúmulo do efeito

do pulso com o efeito Doppler tem o efeito inverso ao da excitação na ressonância, fazendo

a população do estado excitado decair. Para o caso, δ1 = 0 e δ2/2π = 100 MHz, e essa

diferença é a responsável pelos picos duplos.

(a)

0

2

4

6

ρ22×

104

(a)

-600 -400 -200 0 200 400 6000

2

4

6

v(m/s)

ρ33×

107

(b)

Figura 6.4: Distribuição das populações (a) ρ22 e (b) ρ33 por velocidade. As mudanças entre acondição construtiva ou destrutiva da interferência gera os picos duplos em (b), devido aos valoresdiferentes das dessintonias de campo: δ1 = 0 e δ2/2π = 100 MHz.

50

6.2 SOLUÇÃO NA GPU PARA ÁTOMOS DE DOIS NÍVEIS

Na seção anterior, a solução para a população ρ22 com aplicação da distribuição

Maxwell-Boltzman de velocidades tem a forma de picos de excitação apresentada na

Figura 6.4a.

O átomo em ressonância, isto é, com δ = 0, oscila na frequência do campo, e um

átomo com velocidade v 6= 0 oscila na frequência ωc + kv 6= ωc [6], supondo ω21 = ωc.

Assim, entre dois pulsos o campo oscila ωcTR vezes, enquanto o átomo oscila (ω21 +

kv)TR vezes. Se a diferença entre esses números de oscilações for um número inteiro, a

interferência é construtiva, então

(ω21 + kv)TR − ωcTR = 2πn, n = 0, 1, 2... (6.1)

Sendo ω21 = ωc,

kvTR = 2πn. (6.2)

Como k = 2π/λ

vn =λ

TRn, n = 0, 1, 2..., (6.3)

que é a condição de interferência construtiva. Portanto, entre dois picos adjacentes a

diferença de velocidades é

∆v =λ

TR(6.4)

Utilizando os parâmetros do problema, isto é, comprimento de onda do campo λ = 780

nm e TR = 10 ns, chegamos a uma diferença de velocidades ∆v = 78 m/s, que é a diferença

de velocidades entre os picos de excitação na Figura 6.4a.

Para calcular esses resultados, integramos a solução para cada uma das velocidades

da distribuição. Para uma precisão da variação de ∆v = 1 m/s , integramos 1000 vezes.

Para uma precisão maior, como ∆v = 0,001 m/s, integramos 106 vezes, o que torna

o problema de solução computacional custosa, embora paralelizável, já que os cálculos

podem ser realizados separadamente.

Realizamos os testes para a solução desse problema em três processadores e cinco

placas de vídeo distintas. A solução na CPU (Apêndice 3) foi desenvolvida em linguagem

C, compilada com GCC 4.8 ou 4.9. A solução na GPU (Apêndice 4) utilizou o framework

51

CUDA-C, compilada com NVCC em versão compatível com cada placa de vídeo testada,

conforme Tabela 6.1.

Tabela 6.1: GPUs nVidia utilizadas nos testes.

Hardware Características Versão do Cuda Capacidade computacionalGT 210 Baixo custo 5.5 1.1GT 310M Plataforma móvel 6.5 1.1GTX 850M Plataforma móvel 7.0 5.0GTX 560 Intermediário 7.0 3.2GTX 760 Ti Intermediário 7.5 5.0

A capacidade computacional da GPU é um nível de processamento que abrange

diferenças na biblioteca CUDA e no hardware das GPUs, conforme o desenvolvimento

incremental da tecnologia dos dispositivos [7].

As três CPUs são exemplos significativos de configurações representativas e cate-

gorizáveis: um Intel Core2Duo, processador legado com sete anos de uso, um Intel i5 M

460, desenvolvido para uso em notebooks, e um Intel i5 4460, processador de potencial

intermediário. As GPUs utilizadas foram todos modelos nVidia compatíveis com Cuda,

apresentados na Tabela 6.1.

Além dos testes em separado, testamos três configurações completas de combina-

ções distintas de CPU e GPU, visando realizar comparações específicas de desempenho e

custo, sendo um computador legado, um computador móvel e um montado com foco em

desempenho, conforme a Tabela 6.2.

Tabela 6.2: Máquinas distintas e suas combinações CPUxGPU.

Hardware CaracterísticasIntel Core2Duo e GT 210 Hardware legadoIntel i5 M 480 e GT 310M NotebookIntel i5 4460 e GTX 760 Ti Configuração para desempenho

Inicialmente, comparamos diretamente os tempos de execução entre todos os hardwa-

res. A comparação é direta e visual, e a princípio deixa evidente a diferença entre os dois

modelos de solução. Atingimos a solução das equações de Bloch novamente pelo método

RK4. Os parâmetros constantes ao longo de todos os testes são a duração do pulso de

100fs, o tempo entre pulsos de 10ns e o passo de integração numérica no intervalo en-

tre pulsos de 2, 5ps. Variamos o número de pulsos (e consequentemente a duração da

interação) e, quando aplicável, a faixa de velocidades da distribuição Maxwell-Boltzmann

52

(exceto quando explicitamente mencionados valores diversos, -600 m/s < v < 600 m/s, e

o passo entre velocidades é 1 m/s).

(a) (b)

Figura 6.5: Comparativo entre tempos de execução na CPU e na GPU variando-se o número depulsos do laser. A diferença entre os tempos comparados nos gráficos é da ordem de 102, como sevê no eixo temporal das duas comparações.

A execução na CPU demonstrada na Figura 6.5a deixa evidente que o RK4 cresce

linearmente em função do tamanho do problema a ser resolvido. A comparação com a

execução na GPU (Figura 6.5b) mostra que a solução do problema na GPU também é

linear, embora a inclinação da reta seja menor por um fator próximo de 90. A GPU não

altera a complexidade do tempo de execução, mas dispende recursos computacionais para

solucioná-lo de maneira mais eficiente.

O gasto de recursos da GPU, entretanto, tem um custo mínimo. O trânsito em

duas vias de dados entre a memória principal do computador e a GPU, na ida para

execução e na volta para exibição dos resultados, gasta tempo nem sempre desprezível

[38], fazendo existir um volume mínimo de dados para o qual o uso da GPU se torna

efetivamente vantajoso. Para o problema em análise, variamos o número de threads na

GPU em paralelo e um número compatível de iterações na CPU. A Figura 6.6 traz os

resultados comparados. Observamos os pontos de interseção entre as curvas, que indicam

quando a solução na GPU se torna temporalmente vantajosa.

Uma vez solucionadas as equações de Bloch para cada velocidade da distribui-

ção Maxwell-Boltzmann do vapor atômico de rubídio, variamos o tamanho da lista de

execução por meio da variação da faixa de velocidades. Utilizamos convencionalmente o

intervalo −600 m/s < v < 600 m/s para as soluções gerais. Para as variações seguintes,

53

Figura 6.6: Evolução do tempo de execução variando-se o número de threads na GPU e o númerode iterações na CPU.

fazemos vmin = −600 m/s e vmax cresce conforme o tamanho do problema, a princípio em

incrementos de 1 m/s. Não utilizamos a distribuição incompleta gerada por essas varia-

ções para nenhum fim, adotando o método somente para a comparação de desempenho

computacional de uma faixa de velocidades de tamanho arbitrário.

Notamos que, conforme esperado, a CPU executa as tarefas individuais mais rapi-

damente, e que a GPU, conforme igualmente postulado e demonstrado extensivamente,

vence conforme o volume de dados tratados cresce. Na Tabela 6.3 expressamos o tamanho

da faixa de velocidades da distribuição Maxwell-Boltzman solucionadas pelas equações de

Bloch para o qual a GPU se torna vantajosa em comparação à GPU.

Tabela 6.3: Comparações CPUxGPU das máquinas em operação e o respectivo tamanho do arrayde velocidades a partir do qual o tempo de execução na GPU é menor.

Hardware comparado Dimensão do arrayIntel Core2Duo x GT 210 27Intel i5 M 480 x GT 310M 28Intel i5 4460 x GTX 760 Ti 55

Vemos nas Figuras 6.7a, 6.7b e 6.7c que a evolução temporal de execução da GPU

é constante para algumas faixas de tamanho do array de velocidades, e o crescimento para

faixa seguinte se dá em degrau, o que é compatível com o percebido por [41]: a latência

é constante enquanto o array a ser executado couber no cache utilizado. Conforme a

faixa cresce, o número de conjuntos de cache em uso cresce, e para cada novo conjunto

usado sobe-se um degrau. Essa característica permite a deduzir reversamente o tamanho

54

do cache [41].

0 5 0 1 0 0 1 5 0 2 0 0 2 5 08 0 09 0 0

1 0 0 01 1 0 01 2 0 01 3 0 01 4 0 01 5 0 01 6 0 01 7 0 0

(a)

0 5 0 1 0 0 1 5 0 2 0 0 2 5 05 0 0

6 0 0

7 0 0

8 0 0

9 0 0

1 0 0 0

(b)

0 1 2 8 2 5 6 3 8 4 5 1 2 6 4 0 7 6 8 8 9 66 0 08 0 0

1 0 0 01 2 0 01 4 0 01 6 0 01 8 0 02 0 0 02 2 0 0

(c)

Figura 6.7: Tempo de execução em função do número de threads executadas na GPU.

As duas formas de resolver o mesmo problema deixam evidente a diferença exis-

tente entre elas. A GPU se destaca sobre a CPU em uma diferença da ordem daquela

entre poucos segundos e dezenas de minutos para o problema em análise, obviamente

paralelizável, o que permanece verdade mesmo quando se compara a placa de vídeo de

entrada GT 210 com o processador i5 4460, de poder intermediário. Estabelecida essa

superioridade, aprofundamos agora a análise do funcionamento comparado entre as GPUs.

Uma vez que se usa as GPUs principalmente por poder de processamento e de-

sempenho, interessa-nos saber as melhores formas de uso de memória e processamento

visando minimizar o tempo de processamento. A primeira variável testada é a configu-

ração blocos x threads. Embora parte da literatura recomende a consideração cuidadosa

da taxa de ocupação do cache como otimização, análises mais detidas como a de Volkov

[42] demonstram que o problema é na verdade mais complexo, o que os testes realizados

55

confirmam.

Na Figura 6.8 variamos o número de threads por bloco. Na Figura 6.9 variamos

também o tamanho do array de velocidades. Vemos algumas constantes em todos os

modelos analisados. O uso de muitas threads por bloco e de muitos blocos de poucas

threads é notoriamente ineficiente. Podemos notar uma faixa onde a relação blocos x

threads é de eficiência semelhante. A tendência de subida entre Nb× 32 e Nb× 256, onde

Nb é o número de blocos, não se confirma integralmente, com máximos locais distintos

nos modelos.

0 5 0 1 0 0 1 5 0 2 0 0 2 5 01 5 0 03 0 0 04 5 0 06 0 0 07 5 0 09 0 0 0

1 0 5 0 0

0 2 5 6 5 1 2 7 6 8 1 0 2 44 0 06 0 08 0 0

1 0 0 01 2 0 01 4 0 01 6 0 01 8 0 02 0 0 02 2 0 02 4 0 02 6 0 0

Figura 6.8: Tempo de execução em função da proporção threads/bloco. Neste resultado o númerode threads é fixo; a variação acontece na quantidade de threads por bloco.

0 2 0 0 4 0 0 6 0 0 8 0 0 1 0 0 04 0 0

5 0 0

6 0 0

7 0 0

1 1 0 1 0 0 1 0 0 06 0 08 0 0

1 0 0 01 2 0 01 4 0 01 6 0 01 8 0 02 0 0 02 2 0 0

Figura 6.9: Tempo de execução em função do número threads para um bloco.

Não é seguro apontar uma solução ótima para a relação blocos x threads, mas é

evidentemente possível indicar uma solução aceitável para o tempo de desempenho na

faixa em que o número de threads fica entre 32 e 256, para um problema com 1024

execuções paralelas.

Interessa-nos, entretanto, não apenas uma solução mais rápida mas, principal-

mente, uma solução correta. A Figura 6.10 traz a comparação entre as populações fra-

56

cionárias ρ22 resultantes do cálculo na GPU e na CPU. Apesar do resultado geral ser

compatível em ambas, há uma diferença a partir do quinto dígito significativo em valores

absolutos.

Identificamos que as funções matemáticas exp e sech retornam valores ligeiramente

diferentes na última casa significativa para suas implementações na biblioteca padrão C

math.h e na biblioteca matemática CUDA C, o que é a fonte dessa diferença nos resultados

entre as soluções.

Figura 6.10: Valores absolutos da diferença entre a solução da distribuição população ρ22 entrea CPU e a GPU.

Por fim, ainda se faz necessário prever o ganho de desempenho do uso de parale-

lismo na GPU para um problema físico mais realista. O uso de uma faixa de velocidades de

103 é um problema que pode ser considerado pequeno, tanto para a solução das equações

de Bloch em outros contextos quando para as GPUs mais recentes. Assim, aumentou-se

a ordem do tamanho da faixa de velocidades até 106.

A Figura 6.11 traz a comparação visual dos tempos de execução. Para um problema

pequeno, da ordem de 103 velocidades, a solução na CPU i5 4460 é vinte vezes mais lenta

que na GTX 760 Ti. O ganho da GT 210, por sua vez, é de apenas 4,5. Quando o

problema é da ordem de 105, a GT 210 é 43 vezes superior ao i5 4460 em desempenho, e a

GTX 760 é cerca de 900 vezes mais rápida. Na faixa de 106 velocidades, a superioridade

da GT 210 sobre a CPU cai para um fator próximo de 30, entretanto a GTX 760 continua

aumentando sua diferença para um fator próximo de 980 vezes.

57

Figura 6.11: Tempo de execução em função do tamanho do array de velocidades para i5 4460 edois exemplos extremos: a placa de menor poder computacional dos testes, GT210, e a superiorGTX 760 Ti.

6.2.1 Publicações e participações em eventos

Da presente seção, o resumoDensity matrix calculations of Doppler-broadened

atomic systems implemented on GPUs foi selecionado para apresentação no Encon-

tro de Física 2016 da SBF em Natal/RN em forma de banner (Apêndices 5 e 6 e Anexo

1). O tema também foi assunto de seminário apresentado ao grupo de pesquisa Estru-

tura da Matéria e Física Computacional do Departamento de Física da UNIR Campus de

Ji-Paraná (Apêndice 7).

6.3 SOLUÇÃO NA GPU PARA ÁTOMOS DE TRÊS NÍVEIS DO TIPO Λ

Para os resultados desta seção utilizamos as equações de Bloch representativas

de um sistema atômico do tipo Λ, conforme discutido na subseção 4.6.1. Alcançamos as

soluções numéricas também através do método RK4, com programa paralelo desenvolvido

em linguagem CUDA-C, compilado com NVCC versão 7.5 (Anexo 2). Para a solução na

CPU, utilizamos um código em linguagem C++ compilado em GCC 4.9 ou em Microsoft

Visual Studio 2015 (Anexo 3).

58

O hardware testado consiste em dois processadores Intel i5, um da série 4200 M e

outro da série 4460. As duas placas de vídeo nVidia utilizadas nos testes foram a GTX

850 M e a GTX 760 Ti.

Integramos as soluções para uma interação com 100 pulsos de duração temporal

Tp = 100 fs e frequência inicial fR = 100 MHz. Nessas condições, variamos fR em

intervalos regulares para cada passo da solução. Outros parâmetros incluem γ/2π = 2,5

MHz, ω1 = 0, ω2/2π = 6,8 GHz e ω3/2π = 384 THz. Para a frequência de Rabi, adotamos

Ω0 = γ/5

Na Figura 6.13 apresentamos a população ρ33 e a coerência σ12 em função da

variação da taxa de repetição δfR. Observamos que ρ33 atinge seu valor máximo e logo

em seguida vai a zero, no mesmo ponto em que σ12 tem seu valor máximo, de acordo com

o esperado, em conformidade com estudos recentes realizados na área [21].

Tais resultados são compatíveis com a transparência eletromagneticamente indu-

zida discutida na seção 2.5 e respectivas referências. O crescimento da população ρ33

ocorre ao se aproximar da ressonância de dois fótons, e vai a zero exatamente nessa res-

sonância, onde σ12 tem seu valor máximo. Nos detalhes (c) e (d) da Figura 6.13 vemos

os picos da ressonância de um fóton.

A melhora de tempo entre a execução na CPU e na GPU varia, neste caso, entre

25 e 40 vezes, dependendo do hardware comparado. A Figura 6.12 traz uma comparação

visual dos dados de execução em cada CPU e GPU utilizada para a solução.

Para este problema não foi possível carregar todos os dados a se calcular na GPU,

o que levou à necessidade de 36 chamadas de kernel, o que reduziu drasticamente o ganho

de performance em relação às soluções da seção anterior. Contudo, o ganho ainda é

significativo, já que a solução na GPU leva mais de uma hora, enquanto a GPU leva

poucos minutos para tratar o problema.

Os hardwares comparados podem ser divididos em um notebook (processador i5

4200 M e GTX 850 M) e um computador com foco em desempenho (i5 4460 e GTX 760i).

Nessa configuração, os fatores de melhora são mostrados na Tabela 6.4.

Tabela 6.4: Fator de ganho de tempo da GPU em relação à CPU no cálculo dos dados de variaçãoda frequência.

Hardware comparado Fator de melhora (TCPU/TGPU)Intel i5 4200 M x GTX 850 M 25Intel i5 4460 x GTX 760 Ti 14

59

i 5 4 2 0 0 M i 5 4 4 6 0 G T X 8 5 0 M G T X 7 6 0 T i01 02 03 04 05 06 07 0

H a r d w a r e

C P U s

G P U s

Figura 6.12: Tempo de execução para o problema em cada hardware utilizado.

60

Figura 6.13: População ρ33 (a) e σ12 (b) em função da variação da frequência de repetição.Notamos o decréscimo abrupto de ρ33 após o máximo no mesmo ponto onde σ12 é máxima. Abaixotemos o detalhe em torno da origem de (a) e o detalhe em torno da origem de (c).

61

7 CONCLUSÕES

Estudamos sistemas atômicos de dois e três níveis, e suas transições induzidas por

um trem de pulsos ultracurtos, determinando as equações de Bloch ópticas que descrevem

a evolução temporal das populações atômicas de cada estado excitado.

Solucionamos numericamente os sistemas de equações através do método Runge-

Kutta de 4a ordem, com parâmetros compatíveis com vapor atômico de rubídio e com

um laser de Ti:safira pulsado, de forma que o intervalo temporal entre os pulsos (10 ns)

é inferior ao tempo de vida do estado excitado. Sendo assim, observamos que

• os picos populacionais variam em magnitude com o tempo até atingir o equilíbrio,

quando as sequências de picos assumem valores constantes;

• para campos relativamente pouco intensos, quando a frequência de Rabi é uma

fração da taxa de relaxação do estado excitado correspondente, os picos seguem em

crescimento até atingirem o equilíbrio por volta de t = 200ns;

• para campos mais intensos (Ω(t) é igual ou maior que γ22), o equilíbrio é atingido

também por volta de t = 200ns, embora após decair de um valor máximo atingido

anteriormente;

• na variação da dessintonia de campo, há modos discretos de frequência de ressonân-

cia dados por δ = 2πnfr onde n é um número inteiro;

• existe uma excitação seletiva ligada a velocidades específicas da distribuição Maxwell-

Boltzmann, fenômeno vinculado ao efeito doppler.

Em relação à utilização da GPU da solução para átomos de dois níveis com consi-

deração da distribuição de velocidades, notamos que:

• a GPU se destaca em ganho de tempo para o problema em análise mesmo na com-

paração entre placas de baixo custo e processadores de desempenho intermediário;

• há um tamanho mínimo de problema paralelizável a partir do qual a GPU se torna

vantajosa;

• o uso cuidadoso do cache e da configuração de grids e threads tem relação direta

com o ganho de desempenho;

62

• diferenças nas implementações das bibliotecas matemáticas padrão C e CUDA C

dificultam a comparação em problemas mais precisos;

• o uso para problemas que demandem maior precisão pode exigir a definição de

funções matemáticas próprias com a precisão necessária.

Por último, observamos nos resultados a existência de transparência eletromag-

neticamente induzida (EIT) na ressonância após variação da taxa de repetição do laser

pulsado. Quanto à solução na GPU para essa variação da taxa de repetição no sistema Λ

do laser pulsado em uma faixa de -2 a 2 MHZ a partir da ressonância, percebemos que:

• a GPU é vantajosa por um fator grande, mas bastante inferior ao problema da

distribuição Maxwell-Boltzmann das velocidades;

• o fator de melhora do tempo de execução é inferior devido ao volume de dados a se

tratar, que excede as especificações das arquiteturas das GPUs utilizadas;

• o problema pode ser melhor tratado aplicando-se GPUs distribuídas em cluster,

como sugestão para trabalhos posteriores.

63

REFERÊNCIAS

[1] EISBERG, Robert; RESNICK, Robert.Quantum Physics of Atoms, Molecules,

Solids, Nuclei and Particles. Second Edition. JohnWiley & Sons. New York, 1985.

[2] BRANSDEN, B H; JOACHAIN, C J. Physics of atoms and molecules. Longman

Scientific & Technical. Essex, 1983.

[3] HAKEN, H. Light, vol. 2: Laser Light Dynamics. North Holland Pysics Pu-

blishing. Amsterdam, 1985.

[4] CSELE, Mark. Fundamentals of Light Sources and Lasers. John Wiley & Sons.

2004.

[5] SAKURAI, J J; NAPOLITANO, Jim. Mecânica Quântica Moderna. 2a edição.

Bookman. Porto Alegre, 2013.

[6] FOOT, Christopher J. Atomic Physics. Oxford University Press. Oxford, 2004.

[7] COOK, Shane. Cuda Programming: A developer’s guide to parallel compu-

ting with GPUs. Morgan Kaufman. 2013.

[8] HWU, Wen-Mei W (editor). GPU computing gems emerald edition. Elsevier,

2011.

[9] BLOCK, Benjamin; VIRNAU, Peter; PREIS, Tobias. Multi-GPU acceletrated

multi-spin Monte Carlo simulations of the 2D Ising model. Computer Physics

Communications 181, 2010, 1549-1556.

[10] WEIGEL, Martin. Simulating spin models on GPU. Computer Physics Commu-

nications 182, 2011, 1833-1836. Wen-Mei W. Hwu (editor). GPU computing gems

emerald edition. Elsevier, 2011.

[11] HITZ, Breck; EWING, J J; HECHT, Jeff. Introduction to Laser Technology. 3a

Edição. IEEE Press. 1991.

[12] FOX, Mark. Quantum Optics: An Introduction. Oxford University Press. Ox-

ford, 2006.

64

[13] MURTI, Y.; Vijavan, C. Essentials of Nonlinear Optics. Ane Books. Nova Delhi,

2014.

[14] SUTHERLAND, Richard L. Handbook of Nonlinear Optics. 2a Edição. Marcel

Dekker. Nova York, 2003.

[15] BOYD, Robert W. Nonlinear Optics. 3a Edição. Academic Press. Cambridge, 2008.

[16] BOLLER, K J; IMAMOGLU, A; HARRIS, S E. Observation of Electromagne-

tically Induced Transparency. Physical Review Letters, Volume 66, Number 20.

Stanford, 1991.

[17] SCULLY, Marlan O; ZUBAIRY, M. Suhail. Quantum Optics. Cambridge Univer-

sity Press. Cambridge, 1997

[18] NEW, Geoffrey. Nonlinear Optics. Cambridge University Press. Cambridge, 2011.

[19] FLEISCHHAUER, Michael; IMAMOGLU, Atac; MARANGOS, Jhonatan

P.Electromagnetically induced transparency: Optics in coherent media.

Reviews of Modern Physics, Volume 77, 2005.

[20] SAUTENKOV, Vladimir A, et. al. Electromagnetically induced transparency

in rubidium vapor prepared by a comb of short optical pulses. Physical

Review A, 71, 063804, 2005.

[21] MORENO, Marco P; VIANNA, Sandra S. Coherence induced by a train of

ultrashort pulses in a Λ-type system. Journal of the Optical Society of America

B 28(5):1124. 2011

[22] CHANG, Willian S C. Principles of Lasers and Optics. Cambridge University

Press. 2005.

[23] DIELS, Jean-Claude Diels; RUDOLPH, Wolfgang. Ultrashort laser pulse pheno-

mena: Fundamentals, techniques and applications on a femtosecond time

scale. Academic Press, 2a Ed. Albuquerque, 2006.

[24] CUNDIFF, S T. Phase stabilization of ultrashort optical pulses. J. Phys. D:

Appl. Phys. 35, R43–R59, 2002.

65

[25] WELLER, Lee et al. Absolute absorption on rubidium D1 line: including

resonant dipole-dipole interactions. Journal of Physics B: Atomic, Molecular

and Optical Physics, v. 44, n. 19, p. 195006, 2011.

[26] STECK, Daniel A. Rubidium 85 D Line Data. Revisão 2.1.6. Disponível em

http://steck.us/alkalidata. 20 de setembro de 2013.

[27] STIENKEMEIER, F et al. Spectroscopy of alkali atoms (Li, Na, K) attached

to large helium clusters. Z. Phys. D 38, 253—263, 1996.

[28] TAKAHASHI, Y. et al. Spectroscopy of Alkali Atoms and Molecules in Superfluid

Helium. Physical Review Letters, Volume 71, number 7, 1993.

[29] SOARES, A A; ARAUJO, Luís E E. Coherent accumulation of excitation in

the electromagnetically induced transparency of an ultrashort pulse train.

Physical Review A 76, 043818, 2007.

[30] TEMKIN, R J. Excitation of an atom by a train of short pulses. J. Opt. Soc.

Am. B, Vol. 10, No. 5, 1993.

[31] EINWOHNER, T H; WONG, J; GARRISON, J C Analytical solutions for la-

ser excitation of multilevel systems in the rotating-wave approximation.

Physical Review A, Volume 14, Number 4, 1976.

[32] PURI, Ravinder R. Mathematical Methods of Quantum Optics. Springer. Ber-

lim, 2001.

[33] WEBER, Raul Fernando. Arquitetura de Computadores Pessoais. 2a edição.

Sagra Luzzatto. Porto Alegre, 2003.

[34] BROOKSHEAR, J Glenn. Ciência da Computação: Uma visão Abrangente.

5a edição. Bookman. Porto Alegre, 2000.

[35] SANDERS, Jason; KANDROT, Edward. CUDA by example: An introduction

to general-purpouse GPU programming. Addison-Wesley, 2010.

[36] DEMETER, G. Solving the Maxwell-Bloch equations for resonant nonlinear

optics using GPUs. Computer Physics Communications 184.4, 2013.

66

[37] HERMAN, Everton, et. al. Multi-GPU and Multi-CPU Parallelization for

Interactive Physics Simulations. Euro-Par 2010 Parallel Processing, 2010, 235-

246.

[38] CHENG, John; GROSSMAN, Max; MCKERCHER, Ty. Professional CUDA C

Programming. Wrox, Indianapolis, 2014.

[39] RUGGIERO, Márcia A. Gomes; LOPES, Vera Lúcia da Rocha. Cálculo numérico:

aspectos teóricos e computacionais. 2a edição. Makron Books. São Paulo, 1996.

[40] AUMILER, D; BAN T; PICHLER, G. Time dynamics of a multilevel system

excited by a train of ultrashort pulses. Physical Review A 79. 2009

[41] WONG, H, et. al. Demystifying GPU Microarchitecture through Microben-

chmarking. In: Performance Analysis of Systems & Software (ISPASS), 2010 IEEE

International Symposium on. IEEE, 2010. p. 235-246.

[42] VOLKOV, V. Better performance at lower occupancy. UC Berkeley, 2010.

67

APÊNDICE 1: CÓDIGO FONTE C DE PROGRAMA PARA SOLUÇÃO

DAS EQUAÇÕES DE BLOCH EM UM SISTEMA ATÔMICO DE TRÊS

NÍVEIS EM CASCATA

1 #include <math.h>

2 #include <complex.h>

3 #include <stdio.h>

4

5 #define GAMMA_22 2*M_PI*5e6

6 #define GAMMA_33 2*M_PI *660e3

7 #define GAMMA_23 2*M_PI *3.33 e6

8 #define GAMMA_13 2*M_PI *330e3

9 #define GAMMA_12 GAMMA_22 *0.5

10 #define GAMMA_M 0

11 #define PSI 1

12 #define DELTA GAMMA_22

13 #define DELTAM (2* M_PI)/(1e-8)

14 #define RHO11_0 1

15 #define OMEGA_CW 0.01* GAMMA_22

16 #define OMEGA_M 0.01* GAMMA_33

17 #define FILENAME "r3l -res -d_G22 -ocw_G22_10 -om_G33_10.txt"

18 // Tamanho do passo de tempo

19 #define H 5e-15

20 //Tempo maximo

21 #define MAX 4e-7

22 //Tempo do pulso

23 #define Tp 1e-13

24 // Intervalo entre inicio e reinicio dos pulsos

25 #define Tr 1e-8

26

27 double complex rhodot11(float omegacw , double complex sigma12 ,

28 double complex rho22 , double complex rho11 , double complex rho11_0);

29

30 double complex rhodot22(float omegacw , float omegam ,

31 double complex sigma12 , double complex sigma23 , double complex rho22 ,

32 double complex rho33);

33

34 double complex rhodot33(float omegam , double complex sigma23 ,

35 double complex rho33);

36

37 double complex sigmadot12(float deltam , float DELTAcw ,

38 double complex sigma12 , double complex sigma13 , float omegam ,

39 float omegacw , double complex rho22 , double complex rho11);

40

41 double complex sigmadot23(float deltacw , float DELTAm ,

42 double complex sigma23 , double complex sigma13 , float omegam ,

43 float omegacw , double complex rho33 , double complex rho22);

68

44

45 double complex sigmadot13(float deltacw , float deltam , float DELTAcw ,

46 float DELTAm , double complex sigma23 , double complex sigma13 ,

47 double complex sigma12 , float omegam , float omegacw);

48

49 double omega0_t(double o0, double t);

50

51 int main (void)

52 double complex rho11 = RHO11_0;

53 double complex rho22 = 0, rho33 = 0, sigma12 = 0;

54 double complex sigma23 = 0, sigma13 = 0;

55 double complex k1 , k2 , k3 , k4 , l1, l2, l3, l4, m1, m2, m3, m4;

56 double complex n1 , n2 , n3 , n4 , o1, o2, o3, o4, p1, p2, p3, p4;

57 double t=0.0, tp = 0.0, tr = 0.0, h, omega_0 , omegam , grav = 0.0;

58 char pulse = 1;

59 FILE *arq;

60

61 printf ("\n%s\n", FILENAME);

62 arq = fopen(FILENAME , "w");

63 fpr intf (arq , "t (ns)\trho11\trho22 (x1e6)\trho33");

64

65 // RK4

66 while (t < MAX)

67 if (pulse == 1) h = H;

68 else h = H*1;

69

70 // Estabelece a distancia Tr e o reinicio do pulso

71 if (tr < Tr)

72 tr += h;

73

74 else

75 tr = 0.0;

76 pulse = 1;

77

78

79 // Estabelece a duracao do pulso

80 if ((pulse == 1) && (tp < Tp))

81 tp += H;

82

83 else

84 tp = 0.0;

85 pulse = 0;

86

87

88 // Encontra omega_0 em funcao do tempo

89 omega_0 = omega0_t(OMEGA_CW *(Tr/Tp), tr);

90 omegam = omega0_t(OMEGA_M *(Tr/Tp), tr);

91

92 k1 = rhodot11(omega_0 , sigma12 , rho22 , rho11 , RHO11_0);

69

93 l1 = rhodot22(omega_0 , omegam , sigma12 , sigma23 , rho22 , rho33);

94 m1 = rhodot33(omegam , sigma23 , rho33);

95 n1 = sigmadot12(DELTAM , DELTA , sigma12 , sigma13 , omegam ,

96 omega_0 , rho22 , rho11);

97 o1 = sigmadot23(DELTAM , DELTA , sigma23 , sigma13 , omegam ,

98 omega_0 , rho33 , rho22);

99 p1 = sigmadot13(DELTAM , DELTAM , DELTA , DELTA , sigma23 , sigma13 ,

100 sigma12 , omegam , omega_0);

101

102 k2 = rhodot11(omega_0 , sigma12 + (h/2)*n1, rho22 + (h/2)*l1,

103 rho11 + (h/2)*k1 , RHO11_0);

104 l2 = rhodot22(omega_0 , omegam , sigma12 + (h/2)*n1,

105 sigma23 + (h/2)*o1, rho22 + (h/2)*l1 , rho33 + (h/2)*m1);

106 m2 = rhodot33(omegam , sigma23 + (h/2)*o1 , rho33 + (h/2)*m1);

107 n2 = sigmadot12(DELTAM , DELTA , sigma12 + (h/2)*n1,

108 sigma13 + (h/2)*p1, omegam , omega_0 , rho22 + (h/2)*l1,

109 rho11 + (h/2)*k1);

110 o2 = sigmadot23(DELTAM , DELTA , sigma23 + (h/2)*o1,

111 sigma13 + (h/2)*p1, omegam , omega_0 , rho33 + (h/2)*m1,

112 rho22 + (h/2)*l1);

113 p2 = sigmadot13(DELTAM , DELTAM , DELTA , DELTA ,

114 sigma23 + (h/2)*o1, sigma13 + (h/2)*p1,

115 sigma12 + (h/2)*n1, omegam , omega_0);

116

117 k3 = rhodot11(omega_0 , sigma12 + (h/2)*n2, rho22 + (h/2)*l2,

118 rho11 + (h/2)*k2 , RHO11_0);

119 l3 = rhodot22(omega_0 , omegam , sigma12 + (h/2)*n2,

120 sigma23 + (h/2)*o2, rho22 + (h/2)*l2 , rho33 + (h/2)*m2);

121 m3 = rhodot33(omegam , sigma23 + (h/2)*o2 , rho33 + (h/2)*m2);

122 n3 = sigmadot12(DELTAM , DELTA , sigma12 + (h/2)*n2,

123 sigma13 + (h/2)*p2, omegam , omega_0 , rho22 + (h/2)*l2,

124 rho11 + (h/2)*k2);

125 o3 = sigmadot23(DELTAM , DELTA , sigma23 + (h/2)*o2,

126 sigma13 + (h/2)*p2, omegam , omega_0 , rho33 + (h/2)*m2,

127 rho22 + (h/2)*l2);

128 p3 = sigmadot13(DELTAM , DELTAM , DELTA , DELTA ,

129 sigma23 + (h/2)*o2, sigma13 + (h/2)*p2,

130 sigma12 + (h/2)*n2, omegam , omega_0);

131

132 k4 = rhodot11(omega_0 , sigma12 + h*n3, rho22 + h*l3,

133 rho11 + h*k3 , RHO11_0);

134 l4 = rhodot22(omega_0 , omegam , sigma12 + h*n3, sigma23 + h*o3,

135 rho22 + h*l3 , rho33 + h*m3);

136 m4 = rhodot33(omegam , sigma23 + h*o3 , rho33 + h*m3);

137 n4 = sigmadot12(DELTAM , DELTA , sigma12 + h*n3, sigma13 + h*p3,

138 omegam , omega_0 , rho22 + h*l3, rho11 + h*k3);

139 o4 = sigmadot23(DELTAM , DELTA , sigma23 + h*o3, sigma13 + h*p3,

140 omegam , omega_0 , rho33 + h*m3, rho22 + h*l3);

141 p4 = sigmadot13(DELTAM , DELTAM , DELTA , DELTA ,

70

142 sigma23 + h*o3, sigma13 + h*p3, sigma12 + h*n3,

143 omegam , omega_0);

144

145 rho11 += (h/6)*(k1 + 2.0*k2 + 2.0*k3 + k4);

146 rho22 += (h/6)*(l1 + 2.0*l2 + 2.0*l3 + l4);

147 rho33 += (h/6)*(m1 + 2.0*m2 + 2.0*m3 + m4);

148 sigma12 += (h/6)*(n1 + 2.0*n2 + 2.0*n3 + n4);

149 sigma23 += (h/6)*(o1 + 2.0*o2 + 2.0*o3 + o4);

150 sigma13 += (h/6)*(p1 + 2.0*p2 + 2.0*p3 + p4);

151

152 if (grav == 0.0)

153 fpr intf (arq , "\n%e\t%e\t%e\t%e", t/1e-9, creal(rho11),

154 creal(rho22), creal(rho33));

155

156 printf ("\n%e\t%e\t%e\t%e\t%e", t/1e-9, creal(rho11), creal(rho22),

creal(rho33),

157 creal(rho11) + creal(rho22) + creal(rho33));

158

159 if (grav >= 1e-9) grav = 0.0;

160 else grav += h;

161

162 t += h;

163

164 fc lose (arq);

165

166 return 0;

167

168

169 double complex rhodot11(float omegacw , double complex sigma12 ,

170 double complex rho22 , double complex rho11 , double complex rho11_0)

171 return -I*omegacw*sigma12 + conj(-I*omegacw*sigma12) +

172 PSI*GAMMA_22*rho22 - GAMMA_M *( rho11 - rho11_0);

173

174

175 double complex rhodot22(float omegacw , float omegam ,

176 double complex sigma12 , double complex sigma23 , double complex rho22 ,

177 double complex rho33)

178 return I*omegacw*sigma12 + conj(I*omegacw*sigma12) -

179 I*omegam*sigma23 + conj(-I*omegam*sigma23) -

180 (GAMMA_22 + GAMMA_M)*rho22 + GAMMA_33*rho33;

181

182

183 double complex rhodot33(float omegam , double complex sigma23 ,

184 double complex rho33)

185 return I*omegam*sigma23 + conj(I*omegam*sigma23) -

186 (PSI*GAMMA_33 + GAMMA_M)*rho33*0 - GAMMA_33*rho33;

187

188

189 double complex sigmadot12(float deltacw , float DELTAcw ,

71

190 double complex sigma12 , double complex sigma13 , float omegam ,

191 float omegacw , double complex rho22 , double complex rho11)

192 return (I*( deltacw - DELTAcw) - GAMMA_12 - GAMMA_M)*sigma12 -

193 I*omegam*sigma13 + I*omegacw *(rho22 -rho11);

194

195

196 double complex sigmadot23(float deltam , float DELTAm ,

197 double complex sigma23 , double complex sigma13 , float omegam ,

198 float omegacw , double complex rho33 , double complex rho22)

199 return (I*( deltam + DELTAm) - GAMMA_23 - GAMMA_M)*sigma23 +

200 I*omegacw*sigma13 + I*omegam *(rho33 -rho22);

201

202

203 double complex sigmadot13(float deltacw , float deltam , float DELTAcw ,

204 float DELTAm , double complex sigma23 , double complex sigma13 ,

205 double complex sigma12 , float omegam , float omegacw)

206 return (I*( deltacw + deltam + DELTAcw - DELTAm) - GAMMA_13 -

207 GAMMA_M)*sigma13 + I*omegacw*sigma23 - I*omegam*sigma12;

208

209

210 double omega0_t(double o0, double t)

211 double a = 1/cosh (1.76*(t/Tp));

212 return o0*a;

213

72

APÊNDICE 2: CÓDIGO FONTE C DE PROGRAMA QUE DISTRIBUI

AS POPULAÇÕES POR VELOCIDADE EM UM SISTEMA ATÔMICO DE

TRÊS NÍVEIS EM CASCATA

1 #include <math.h>

2 #include <complex.h>

3 #include <stdio.h>

4 #include <string.h>

5

6 // Constantes

7

8 #define GAMMA_22 2*M_PI*5e6

9 #define GAMMA_33 2*M_PI *660e3

10 #define GAMMA_23 2*M_PI *3.33 e6

11 #define GAMMA_13 2*M_PI *330e3

12 #define GAMMA_12 GAMMA_22 *0.5

13 #define GAMMA_M 0

14 #define PSI 1

15 #define DELTA 0.0

16 #define DELTAM 0

17 #define DELTAM_32 2*M_PI *20e6

18 // Pop. inicial de rho11

19 #define RHO11_0 1

20 #define OMEGA_CW 0.1* GAMMA_22

21 #define OMEGA_M 0.1* GAMMA_33

22 #define FILENAME "r3l -res -ocw_G22_10 -om_G33_10.txt"

23 // Tamanho do passo de tempo

24 #define H 5e-15

25 //Tempo maximo

26 #define MAX 4e-7

27 //Tempo do pulso

28 #define Tp 1e-13

29 // Intervalo entre inicio e reinicio dos pulsos

30 #define Tr 1e-8

31

32 // U = sqrt(M/(2*kb*T))

33 #define U 4.13e-3

34 #define LAMBDA1 780e-9

35 #define LAMBDA2 780e-9

36 #define MINV -600.0

37 #define MAXV 600.0

38

39 double complex rhodot11(float omegacw , double complex sigma12 ,

40 double complex rho22 , double complex rho11 ,

41 double complex rho11_0)

42 return -I*omegacw*sigma12 + conj(-I*omegacw*sigma12) +

43 PSI*GAMMA_22*rho22 - GAMMA_M *( rho11 - rho11_0);

73

44

45

46 double complex rhodot22(float omegacw , float omegam ,

47 double complex sigma12 , double complex sigma23 ,

48 double complex rho22 ,double complex rho33)

49 return I*omegacw*sigma12 + conj(I*omegacw*sigma12) -

50 I*omegam*sigma23 + conj(-I*omegam*sigma23) -

51 (GAMMA_22 + GAMMA_M)*rho22 + GAMMA_33*rho33;

52

53

54 double complex rhodot33(float omegam , double complex sigma23 ,

55 double complex rho33)

56 return I*omegam*sigma23 + conj(I*omegam*sigma23) -

57 (PSI*GAMMA_33 + GAMMA_M)*rho33*0 - GAMMA_33*rho33;

58

59

60 double complex sigmadot12(float deltacw , float DELTAcw ,

61 double complex sigma12 , double complex sigma13 , float omegam ,

62 float omegacw , double complex rho22 , double complex rho11)

63 return (I*( deltacw - DELTAcw) - GAMMA_12 - GAMMA_M)*sigma12 -

64 I*omegam*sigma13 + I*omegacw *(rho22 -rho11);

65

66

67 double complex sigmadot23(float deltam , float DELTAm ,

68 double complex sigma23 , double complex sigma13 , float omegam ,

69 float omegacw , double complex rho33 , double complex rho22)

70 return (I*( deltam + DELTAm) - GAMMA_23 - GAMMA_M)*sigma23 +

71 I*omegacw*sigma13 + I*omegam *(rho33 -rho22);

72

73

74 double complex sigmadot13(float deltacw , float deltam ,

75 float DELTAcw , float DELTAm , double complex sigma23 ,

76 double complex sigma13 , double complex sigma12 , float omegam ,

77 float omegacw)

78 return (I*( deltacw + deltam + DELTAcw - DELTAm) - GAMMA_13 -

79 GAMMA_M)*sigma13 + I*omegacw*sigma23 - I*omegam*sigma12;

80

81

82

83 double omega0_t(double o0, double t)

84 double a = 1/cosh (1.76*(t/Tp));

85 return o0*a;

86

87

88 double p(int v)

89 return (U/sqrt(M_PI))*exp(-(U*U)*(v*v));

90

91

92 int main (void)

74

93 double complex rho11 = RHO11_0;

94 double complex rho22 = 0, rho33 = 0, sigma12 = 0;

95 double complex sigma23 = 0, sigma13 = 0;

96 double complex k1 , k2 , k3 , k4 , l1, l2, l3, l4, m1, m2, m3, m4;

97 double complex n1 , n2 , n3 , n4 , o1, o2, o3, o4, p1, p2, p3, p4;

98 double t=0.0, tp = 0.0, tr = 0.0, h, omega_0 , omegam;

99 char pulse = 1, filev [100];

100 FILE *arqv;

101 float v;

102 double DELTA1 , DELTA2;

103

104 printf (".");

105 // Arquivo de dados da distribuicao por velocidade

106 sprintf(filev , "r5 -L1_%.0f-L2_%.0f.txt", LAMBDA1 /1e-9,

107 LAMBDA2 /1e-9);

108 arqv = fopen(filev , "w");

109 fpr intf (arqv , "v (m/s)\trho22\trho33");

110

111 for (v = MINV; v <= MAXV; v += 7.8)

112 DELTA1 = ((2* M_PI)/LAMBDA1)*v;

113 DELTA2 = ((2* M_PI)/LAMBDA2)*v;

114

115 // RK4

116 while (t < MAX)

117 // Aplica o menor passo no interior do pulso

118 // No intervalo entre pulsos aplica o fator multiplicador

119 if (pulse == 1)

120 h = H;

121 else h = H*100;

122

123 // Estabelece a distancia Tr e o reinicio do pulso

124 if (tr < Tr)

125 tr += h;

126 else

127 tr = 0.0;

128 pulse = 1;

129

130

131 // Estabelece a duracao do pulso

132 if ((pulse == 1) && (tp < Tp))

133 tp += H;

134

135 else

136 tp = 0.0;

137 pulse = 0;

138

139

140 // Encontra omega_0 em funcao do tempo

141 omega_0 = omega0_t(OMEGA_CW *(Tr/Tp), tr);

75

142 omegam = omega0_t(OMEGA_M *(Tr/Tp), tr);

143

144 k1 = rhodot11(omega_0 , sigma12 , rho22 , rho11 , RHO11_0);

145 l1 = rhodot22(omega_0 , omegam , sigma12 , sigma23 , rho22 , rho33);

146 m1 = rhodot33(omegam , sigma23 , rho33);

147 n1 = sigmadot12(DELTAM ,DELTA1 , sigma12 , sigma13 , omegam ,

148 omega_0 , rho22 , rho11);

149 o1 = sigmadot23(DELTAM_32 , DELTA2 , sigma23 , sigma13 , omegam ,

150 omega_0 , rho33 , rho22);

151 p1 = sigmadot13(DELTAM_32 , DELTAM , DELTA1 , DELTA2 , sigma23 ,

152 sigma13 , sigma12 , omegam , omega_0);

153

154 k2 = rhodot11(omega_0 , sigma12 + (h/2)*n1, rho22 + (h/2)*l1,

155 rho11 + (h/2)*k1 , RHO11_0);

156 l2 = rhodot22(omega_0 , omegam , sigma12 + (h/2)*n1,

157 sigma23 + (h/2)*o1, rho22 + (h/2)*l1 , rho33 + (h/2)*m1);

158 m2 = rhodot33(omegam , sigma23 + (h/2)*o1 , rho33 + (h/2)*m1);

159 n2 = sigmadot12(DELTAM , DELTA1 , sigma12 + (h/2)*n1,

160 sigma13 + (h/2)*p1, omegam , omega_0 , rho22 + (h/2)*l1,

161 rho11 + (h/2)*k1);

162 o2 = sigmadot23(DELTAM_32 , DELTA2 , sigma23 + (h/2)*o1,

163 sigma13 + (h/2)*p1, omegam , omega_0 ,

164 rho33 + (h/2)*m1 , rho22 + (h/2)*l1);

165 p2 = sigmadot13(DELTAM_32 , DELTAM , DELTA1 , DELTA2 ,

166 sigma23 + (h/2)*o1, sigma13 + (h/2)*p1,

167 sigma12 + (h/2)*n1, omegam , omega_0);

168

169 k3 = rhodot11(omega_0 , sigma12 + (h/2)*n2, rho22 + (h/2)*l2,

170 rho11 + (h/2)*k2 , RHO11_0);

171 l3 = rhodot22(omega_0 , omegam , sigma12 + (h/2)*n2,

172 sigma23 + (h/2)*o2, rho22 + (h/2)*l2 , rho33 + (h/2)*m2);

173 m3 = rhodot33(omegam , sigma23 + (h/2)*o2 , rho33 + (h/2)*m2);

174 n3 = sigmadot12(DELTAM , DELTA1 , sigma12 + (h/2)*n2,

175 sigma13 + (h/2)*p2, omegam , omega_0 , rho22 + (h/2)*l2,

176 rho11 + (h/2)*k2);

177 o3 = sigmadot23(DELTAM_32 , DELTA2 , sigma23 + (h/2)*o2,

178 sigma13 + (h/2)*p2, omegam , omega_0 ,

179 rho33 + (h/2)*m2 , rho22 + (h/2)*l2);

180 p3 = sigmadot13(DELTAM_32 , DELTAM , DELTA1 , DELTA2 ,

181 sigma23 + (h/2)*o2, sigma13 + (h/2)*p2,

182 sigma12 + (h/2)*n2, omegam , omega_0);

183

184 k4 = rhodot11(omega_0 , sigma12 + h*n3, rho22 + h*l3,

185 rho11 + h*k3 , RHO11_0);

186 l4 = rhodot22(omega_0 , omegam , sigma12 + h*n3, sigma23 + h*o3,

187 rho22 + h*l3 , rho33 + h*m3);

188 m4 = rhodot33(omegam , sigma23 + h*o3 , rho33 + h*m3);

189 n4 = sigmadot12(DELTAM , DELTA1 , sigma12 + h*n3,

190 sigma13 + h*p3, omegam , omega_0 , rho22 + h*l3,

76

191 rho11 + h*k3);

192 o4 = sigmadot23(DELTAM_32 , DELTA2 , sigma23 + h*o3,

193 sigma13 + h*p3, omegam , omega_0 , rho33 + h*m3,

194 rho22 + h*l3);

195 p4 = sigmadot13(DELTAM_32 , DELTAM , DELTA1 , DELTA2 ,

196 sigma23 + h*o3, sigma13 + h*p3, sigma12 + h*n3,

197 omegam , omega_0);

198

199 rho11 += (h/6)*(k1 + 2.0*k2 + 2.0*k3 + k4);

200 rho22 += (h/6)*(l1 + 2.0*l2 + 2.0*l3 + l4);

201 rho33 += (h/6)*(m1 + 2.0*m2 + 2.0*m3 + m4);

202 sigma12 += (h/6)*(n1 + 2.0*n2 + 2.0*n3 + n4);

203 sigma23 += (h/6)*(o1 + 2.0*o2 + 2.0*o3 + o4);

204 sigma13 += (h/6)*(p1 + 2.0*p2 + 2.0*p3 + p4);

205

206 t += h;

207 //while RK4

208

209 // Gravacao em arquivo da pop em funcao da velocidade

210 fpr intf (arqv , "\n%.0f\t%e\t%e", v, creal(rho22)*p(v),

211 creal(rho33)*p(v));

212 printf ("\n%.0f\t%.0f\t%e\t%e",v/10 + 60, v, creal(rho22)*p(v),

213 creal(rho33)*p(v));

214

215 t = 0.0;

216 tr = 0.0;

217 tp = 0.0;

218 rho11 = RHO11_0;

219 rho22 = 0;

220 rho33 = 0;

221 sigma12 = 0;

222 sigma23 = 0;

223 sigma13 = 0;

224 //for

225 fc lose (arqv);

226 return 0;

227

77

APÊNDICE 3: CÓDIGO FONTE C DE PROGRAMA PARA MEDIÇÕES

NA CPU ENVOLVENDO A SOLUÇÃO PARA SISTEMAS DE DOIS NÍ-

VEIS

1 #include <stdio.h>

2 #include <stdlib.h>

3 #include <math.h>

4 #include <complex.h>

5 #include <time.h>

6

7 #define PI 3.14159265359f

8

9 const float GAMMA_22 = 2*PI*5e6;

10 const float GAMMA_12 = 2*PI*5e6*0.5; // GAMMA22 /2

11 const float OMEGA_0 = 2*PI*5e6*0.1; // GAMMA22 /10

12

13 #define DELTA 0

14 #define H 5e-15f

15 #define MAX 4e-7f

16 #define Tp 1e-13f

17 #define Tr 1e-8f

18 #define U 4.13e-3f // U = sqrt(M/(2*kb*T))

19 #define LAMBDA1 780e-9f

20 #define MINV -600.0f

21 #define MAXV 599.0f

22 #define PASSO 1.0f

23

24 float p(int v)

25 return exp(-(U*U)*(v*v));

26

27

28 float complex f_sigmadot(float complex sigma_12 ,

29 float complex rho_22 , float delta , float omega_0);

30

31 float complex f_rhodot(float complex sigma_12 , float complex rho_22 , float omega_0);

32

33 float complex RK4(float delta , float omega_t0);

34

35 float omega0_t(float e0 , float t);

36

37

38 int main(void)

39 const float delta_mult = ((2*PI)/LAMBDA1);

40 float v;

41 float delta1;

42 float complex rho22;

43 FILE *arqp , *arqt;

78

44 clock_t start , end;

45 float htimedif;

46

47 printf ("Executando na CPU");

48 //CPU

49 time(&start);

50 arqp = fopen("pop_cpu_40p.txt", "w");

51 fpr intf (arqp , "v (m/s)\trho22");

52

53 for (v = MINV; v <= MAXV; v += PASSO)

54 delta1 = delta_mult*v;

55 rho22 = RK4(delta1 , OMEGA_0);

56 fpr intf (arqp , "\n%.0f\t%e", v, creal(rho22)*p(v));

57 printf ("\nCPU %.0f\t%e", v, creal(rho22)*p(v));

58

59

60 fc lose (arqp);

61 time(&end);

62 htimedif = difftime(end , start);

63

64 printf ("\nTempo na CPU: %.1f s",

65 htimedif);

66

67 arqt = fopen("timediff.txt", "w");

68 fpr intf (arqt , "CPU");

69 fpr intf (arqt , "%f", htimedif);

70 fc lose (arqt);

71

72 return 0;

73

74

75 float complex f_sigmadot(float complex sigma_12 ,

76 float complex rho_22 , float delta , float omega_0)

77 return (I*delta - GAMMA_12)*sigma_12 -

78 I*omega_0 *(1 - 2* rho_22);

79

80

81 float complex f_rhodot(float complex sigma_12 , float complex rho_22 ,

82 float omega_0)

83 float complex i_omega_sig = I*omega_0*sigma_12;

84

85 float complex rho_22_dot = -(GAMMA_22*rho_22)

86 + i_omega_sig + conj(i_omega_sig);

87

88 return rho_22_dot;

89

90

91 float complex RK4(float delta , float omega_t0)

92 const float O0 = omega_t0 *(Tr/Tp);

79

93 float complex rho_22 = 0;

94 float complex sigma_12 = 0;

95 float complex k1s , k2s , k3s , k4s;

96 float complex k1r , k2r , k3r , k4r;

97 float t=0, tr = 0.0f, omega_0 , h=H;

98

99 while (t < MAX)

100 if (tr >= Tr)

101 tr = 0.0f;

102 h = H;

103

104 else if ((tr >= Tp*6) && (omega_0 != 0))

105 h = H*500;

106 omega_0 = 0;

107

108

109 if (tr < Tp*6)

110 omega_0 = omega0_t(O0 , tr - Tp*3);

111

112 k1s = f_sigmadot(sigma_12 , rho_22 , delta , omega_0);

113 k1r = f_rhodot(sigma_12 , rho_22 , omega_0);

114

115 k2s = f_sigmadot(sigma_12 + (h/2)*k1s ,

116 rho_22 + (h/2)*k1r , delta , omega_0);

117 k2r = f_rhodot(sigma_12 + (h/2)*k1s ,

118 rho_22 + (h/2)*k1r , omega_0);

119

120 k3s = f_sigmadot(sigma_12 + (h/2)*k2s ,

121 rho_22 + (h/2)*k2r , delta , omega_0);

122 k3r = f_rhodot(sigma_12 + (h/2)*k2s ,

123 rho_22 + (h/2)*k2r , omega_0);

124

125 k4s = f_sigmadot(sigma_12 + h*k3s ,

126 rho_22 + h*k3r , delta , omega_0);

127 k4r = f_rhodot(sigma_12 + h*k3s ,

128 rho_22 + h*k3r , omega_0);

129

130 sigma_12 += (h/6)*(k1s + 2.0* k2s + 2.0* k3s + k4s);

131 rho_22 += (h/6)*(k1r + 2.0* k2r + 2.0* k3r + k4r);

132

133 t += h;

134 tr += h;

135

136

137 return rho_22;

138

139

140 float omega0_t(float o0 , float t)

141 float a = 1/coshf (1.76*(t/Tp));

80

142 return o0*a;

143

81

APÊNDICE 4: CÓDIGO FONTE CUDA-C DE PROGRAMA PARA MEDI-

ÇÕES NA GPU ENVOLVENDO A SOLUÇÃO PARA SISTEMAS DE DOIS

NÍVEIS

1 #include <stdlib.h>

2 #include <stdio.h>

3 #include <math.h>

4 #include <complex.h>

5 #include <cuComplex.h>

6 #include "cuda_runtime.h"

7 #include "device_launch_parameters.h"

8

9 #define MINV -500

10 #define MAXV 500

11 #define PASSO 1 // Determina o tamanho do array

12 #define THREADN 250

13 #define BLOCKX 4

14 #define BLOCKY 1

15 #define LAMBDA1 780e-9

16 #define U 4.13e-3

17

18 #define PI 3.14159265359

19

20 #define GAMMA_22 2*PI*5e6

21 #define GAMMA_12 GAMMA_22 *0.5

22 #define OMEGA_0 GAMMA_22 *0.1

23 #define H 5e-15f

24 #define MAX 4e-7f

25 #define Tp 1e-13f

26 #define Tr 1e-8f

27 #define FILENAME "rG-L780.txt"

28

29 const float ARRAY_SIZE = (MAXV - MINV)/PASSO;

30

31 __device__ cuFloatComplex cMultFloat(cuFloatComplex comp , float mult)

32 return cuCmulf(make_cuFloatComplex(mult , 0), comp);

33

34

35 __device__ cuFloatComplex f_sigmadot(cuFloatComplex s12 ,

36 cuFloatComplex r22 , float delta , float omega_0)

37

38 cuFloatComplex i_delta = make_cuFloatComplex (0, delta);

39 cuFloatComplex g12s12 = cMultFloat(s12 , -GAMMA_12);

40 cuFloatComplex i_omega = make_cuFloatComplex (0, -omega_0);

41 cuFloatComplex omega_rho = cMultFloat(r22 , -2);

42

43 cuFloatComplex res = cuCmulf(i_delta , s12);

82

44 res = cuCaddf(res , g12s12);

45 res = cuCaddf(res , i_omega);

46 omega_rho = cuCmulf(i_omega , omega_rho);

47 res = cuCaddf(res , omega_rho);

48

49 return res;

50

51

52

53 __device__ cuFloatComplex f_rhodot(cuFloatComplex s12 ,

54 cuFloatComplex r22 , float omega_0)

55

56 cuFloatComplex i_omega = make_cuFloatComplex (0, omega_0);

57 cuFloatComplex g22r22 = cMultFloat(r22 , -GAMMA_22);

58 cuFloatComplex i_omega_sig = cuCmulf(i_omega , s12);

59 cuFloatComplex res = cuCaddf(g22r22 , i_omega_sig);

60 res = cuCaddf(res , cuConjf(i_omega_sig));

61

62 return res;

63

64

65

66 __global__ void kdmb(float *d_rho22 , float *d_vel)

67 int idx = threadIdx.x + (blockIdx.y*gridDim.x + blockIdx.x)*blockDim.x;

68 float delta = ((2 * PI) / LAMBDA1)*( d_vel[idx]);

69 cuFloatComplex rho_22 = make_cuFloatComplex (0, 0);

70 cuFloatComplex sigma_12 = make_cuFloatComplex (0, 0);

71 cuFloatComplex k1s , k2s , k3s , k4s;

72 cuFloatComplex k1r , k2r , k3r , k4r;

73 float t = 0.0f, tr = 0.0f, omega_0 , h = H;

74

75 while (t < MAX)

76 if (tr > Tr)

77 tr = 0.0f;

78 h = H;

79

80 else if (tr > Tp)

81 h = H*500;

82

83

84 omega_0 = OMEGA_0 *(Tr / Tp)*(1 / cosh (1.76*( tr / Tp)));

85

86 k1s = f_sigmadot(sigma_12 , rho_22 , delta , omega_0);

87 k1r = f_rhodot(sigma_12 , rho_22 , omega_0);

88

89 k2s = f_sigmadot(cuCaddf(sigma_12 , cMultFloat(k1s , h / 2)),

90 cuCaddf(rho_22 , cMultFloat(k1r , h / 2)),

91 delta , omega_0);

92 k2r = f_rhodot(cuCaddf(sigma_12 , cMultFloat(k1s , h / 2)),

83

93 cuCaddf(rho_22 , cMultFloat(k1r , h / 2)),

94 omega_0);

95

96 k3s = f_sigmadot(cuCaddf(sigma_12 , cMultFloat(k2s , h / 2)),

97 cuCaddf(rho_22 , cMultFloat(k2r , h / 2)),

98 delta , omega_0);

99 k3r = f_rhodot(cuCaddf(sigma_12 , cMultFloat(k2s , h / 2)),

100 cuCaddf(rho_22 , cMultFloat(k2r , h / 2)),

101 omega_0);

102

103 k4s = f_sigmadot(cuCaddf(sigma_12 , cMultFloat(k3s , h)),

104 cuCaddf(rho_22 , cMultFloat(k3r , h)),

105 delta , omega_0);

106 k4r = f_rhodot(cuCaddf(sigma_12 , cMultFloat(k3s , h)),

107 cuCaddf(rho_22 , cMultFloat(k3r , h)),

108 omega_0);

109

110 sigma_12 = cuCaddf(sigma_12 ,

111 cMultFloat(cuCaddf(cuCaddf(cuCaddf(k1s , cMultFloat(k2s , 2)),

112 cMultFloat(k3s , 2)), k4s), h/6));

113 rho_22 = cuCaddf(rho_22 ,

114 cMultFloat(cuCaddf(cuCaddf(cuCaddf(k1r , cMultFloat(k2r , 2)),

115 cMultFloat(k3r , 2)), k4r), h/6));

116

117 t += h;

118 tr += h;

119

120

121 d_rho22[idx] = cuCrealf(rho_22)*((U/sqrt(PI))*exp(-U*U*d_vel[idx]*d_vel[idx]));

122

123

124 int main(int argc , char *argv [])

125 int i;

126 int size = (ARRAY_SIZE)*sizeof(float);

127 float *h_rho22 = (float*) malloc(size);

128 float *d_rho22;

129 float *h_vel = (float *) malloc(size);

130 float *d_vel;

131 float v;

132 FILE *arqp , *arqt;

133 cudaEvent_t start , stop;

134 float time;

135 int threads=THREADN;

136 dim3 grid(BLOCKX , BLOCKY);

137

138 if (argc > 2)

139 threads = atoi(argv [2]);

140

141

84

142 cudaEventCreate (&start);

143 cudaEventCreate (&stop);

144 cudaEventRecord(start , 0);

145

146 v = MINV;

147 for (i = 0; i < ARRAY_SIZE; i++)

148 h_vel[i] = v;

149 v += PASSO;

150

151

152 cudaMalloc((void **)&d_rho22 , size);

153 cudaMalloc((void **)&d_vel , size);

154

155 cudaMemcpy(d_rho22 , h_rho22 , size , cudaMemcpyHostToDevice);

156 cudaMemcpy(d_vel , h_vel , size , cudaMemcpyHostToDevice);

157

158 kdmb <<<grid , threads >>>(d_rho22 , d_vel);

159

160 cudaMemcpy(h_rho22 , d_rho22 , size , cudaMemcpyDeviceToHost);

161

162 arqp = fopen("pop_gpu_40p_10e6.txt", "w");

163 fpr intf (arqp , "v (m/s)\trho22");

164

165 for (i = 0; i < ARRAY_SIZE; i++)

166 fpr intf (arqp , "\n%.3f\t%e", h_vel[i], h_rho22[i]);

167

168

169 fc lose (arqp);

170

171 cudaEventRecord(stop , 0);

172 cudaEventSynchronize(stop);

173 cudaEventElapsedTime (&time , start , stop);

174

175 printf ("\nTempo na GPU: %3.3f ms \n", time);

176

177 arqt = fopen("timediffGPU_210_1e3.txt", "w");

178 fpr intf (arqt , "GPU");

179 fpr intf (arqt , "\n%f", time);

180 fc lose (arqt);

181

182 cudaFree(d_rho22);

183 cudaFree(d_vel);

184

185 return 0;

186

85

86

APÊNDICE 5: BANNER APRESENTADO NO ENF 2016

Density matrix calculations of Doppler-broadened atomic systemsimplemented on GPUs

Teo Victor R. da Silva and Marco P. M. de SouzaDepartamento de Fısica, Universidade Federal de Rondonia, Ji-Parana/RO, Brazil

[email protected]

AbstractNumerical calculations of the density matrix elements are a time-consuming computational problem, due tothe Doppler broadening that demands the inclusion of the contribution of many group velocities. We usegraphical processing units (GPUs) to accelerate these calculations by parallelism, for the interaction of rubid-ium vapor with a resonant train of ultrashort laser pulses of 100MHz repetition rate. We consider a two-levelatomic system, and solve the Bloch equations in time domain with the standart 4th order Runge-Kutta method.We compare the performance of five Nvidia GPUs and a Core i5 4460 CPU. There is a relative difference be-low 2.2 × 10−5 for the results presented by GPU and CPU. For the GeForce 760 Ti, it is necessary 55 groupvelocities to be faster than CPU. The maximum speedup is 960× for 106 group velocities, which should beuseful for more realistic problems, where the CPU calculations can take several days.

Hardware

Hardware Characteristics CUDA version Compute capacityGT 210 Low cost 5.5 1.1GT 310M Mobile 6.5 1.1GTX 850M Mobile 7.0 5.0GTX 560 Intermediary 7.0 3.2GTX 760 Ti Intermediary 7.5 5.0

Hardware CharacteristicsIntel Core2Duo and GT 210 Legacy hardwareIntel i5 M 480 and GT 310M LaptopIntel i5 4460 and GTX 760 Ti Performance configuration

TheoryThe Bloch equations describe the time evolution of the density matrix elements when interacting with electro-magnetic fields. For a two level system,

ρ11 = −iΩ0(t)σ12 + c.c. + γ22ρ22 (1a)ρ22 = iΩ0(t)σ12 + c.c.− γ22ρ22 (1b)σ12 = (iδ − γ12)σ12 + iΩ0(ρ22 − ρ11) (1c)

The eletric field of the ultrashort train of pulses is

E(t) =

N−1∑

N=0

E0(t− nTR)e−i(ωct−nωcTR+n∆φ) (2)

We represent the pulse envelopment with a hyperbolic secant function

E0(t) = E0sech

(1,76t

Tp

)(3)

GPU architecture

Figure 1: Source: Ref [7]

GPU execution model

Figure 2: Source: Ref [8]

Results• We solve the Bloch equations with parameters compatible with Rubidium vapor of 85Rb isotope, interacting

with a standard commercial pulsed Ti:sapphire laser.

• Numerical calculations with Runge-Kutta 4th order (RK4) method.

• CPU tests are performed with a C code,and the GPU tests with CUDA-C.

• The solution has the form of excitation peaks

- 6 0 0 - 4 0 0 - 2 0 0 0 2 0 0 4 0 0 6 0 00 , 0 0

0 , 0 2

0 , 0 4

0 , 0 6

0 , 0 8

ρ 22

V e l o c i t y ( m / s ) 0 5 0 1 0 0 1 5 0 2 0 0 2 5 002 0 04 0 06 0 08 0 0

1 0 0 01 2 0 01 4 0 01 6 0 0

Exec

ution

time (

ms)

G P U t h r e a d n u m b e r o r C P U i t e r a t i o n s

I n t e l C o r e 2 D u o I n t e l i 5 M 4 8 0 I n t e l i 5 4 4 6 0 G T 2 1 0 G T 3 1 0 M G T X 7 6 0 T i

• We integrate the solution for each velocity on the distribution.

• The RK4 method has a linear time complexity running on a traditional CPU code. The GPU code maintainsthe time complexity, but has an overall better performance.

• For architectural reasons, there is a minimum number of group velocities for the GPU to become a betteroption.

0 2 5 6 5 1 2 7 6 8 1 0 2 405 0 0

1 0 0 01 5 0 02 0 0 02 5 0 0

Exec

ution

time (

ms)

T h r e a d s p e r b l o c k

4 0 p u l s e s 1 0 0 p u l s e s

G T X 8 5 0 - 1 0 2 4 t h r e a d s

1 0 3 1 0 4 1 0 5 1 0 61 0 - 1

1 0 0

1 0 1

1 0 2

1 0 3

1 0 4

Exec

ution

time (

s)V e l o c i t i e s a r r a y s i z e

G T X 7 6 0 T i G T 2 1 0 i 5 4 4 6 0

• The solution of the Bloch equations for 103 group velocities is still a small problem for an adequate GPUx-CPU comparison.

• We solved for bigger problem sizes, up to 106 group velocities.

• GeForce GTX 760 Ti GPU is 980 times faster than as Intel Core i5 4460 CPU.

• The execution time keeps reducing with the increasing of group velocities

Conclusions• GPUs improve the execution time for the problem under analysis even comparing low-cost entry options as

Nvidia GT 210 over a compatible code running on a intermediary CPU as Intel i5 4460.

• There is a minimum problem size for the GPU became advantageous.

• The use of the cache units and the grids, blocks and threads configuration has a direct impact on the perfor-mance improvement.

• The comparisons in this work arbitrarily change the size or precision of the group velocities array, butthe performance improvement should be useful for more realistic physics problems, like velocity-selectivetransitions in multilevel atomic systems.

Forthcoming ResearchModern CPUs are multicore systems, and a fairer comparison should consider this, but the quadcore i5 would,on best case scenario, be four times faster. There are differences on the implementations of mathematical li-braries on the two languages, leading to slight differences, of a maximum module of the order of 10−5. Resultsdemanding superior precision, which is the case for this subject, can force the definition of more appropriatemathematical functions.

References[1] R. J. Temkin. J. Opt. Soc. Am. B, Vol. 10, No. 5, 1993.

[2] S. T. Cundiff. J. Phys. D: Appl. Phys. 35, R43R59, 2002.

[3] Jean-Claude Diels, Wolfgang Rudolph. Academic Press, 2ł Ed. Albuquerque, 2006.

[4] Everton Hermann, et. al. Euro-Par 2010 Parallel Processing, 2010, 235-246.

[5] G. Demeter. Computer Physics Communications 184.4, 2013.

[6] Benjamin Block, Peter Virnau, Tobias Preis. Computer Physics Communications 181, 2010, 1549-1556.

[7] D. B. Kirk and W. W. Hwu, Programming Massively Parallel Processors, Elsevier, Waltham, 2013.

[8] J. Cheng, M. Grossman and T. McKercher, Professional CUDA C Programming, John Wiley and Sons,Indianapolis, 2014.

87

APÊNDICE 6: RESUMO DA APRESENTAÇÃO NO ENF 2016

Density matrix calculations of Doppler-broadened atomic systemsimplemented on GPUs

Teo Victor Resende da Silva and Marco P. M. de SouzaDepartamento de Fısica, Universidade Federal de Rondonia, Ji-Parana - RO, Brazil.

Important subjects in non-linear optics involving resonant interactions between lasers andatomic vapors has been very studied in recent years. We can mention the parametric four-wave mixing, the electromagnetically induced transparency, the photon echo and the slowlight, for example. The Doppler broadening is usually the main contribution to the opticalresponse of an atomic vapor. Thus, the numerical calculations of the density matrix ele-ments must include the contribution of many group velocities, leading to time-consumingcomputations. On the other hand, graphical processing units (GPUs) has been exten-sively used in various fields of science, like molecular dynamics, magnetohydrodynamicssimulations, Maxwell-Bloch equations, Monte Carlo simulations, and various others. Inthis work, we use GPUs to accelerate the calculations of the density matrix of the problemof a Doppler-broadened rubidium vapor in the presence of a resonant train of ultrashortpulses of 100 MHz repetition rate. We solve the Bloch equations in the time domain forthe 5S1/2 → 5P3/2 transition by using the standard fourth-order Runge-Kutta method.We use the Cuda cores of the GPUs to solve the Bloch equations for different atomicgroup velocities in parallel, while the CPU does it serially. We compare the performanceof five GPUs and a Core i5 4460 CPU, where the results present a relative difference below2.2×10−5. For the Geforce GTX 760 Ti, it is necessary 55 group velocities to this GPU tobe faster than the CPU. The maximum speedup is 960×, reached for 106 group velocities.This speedup should be useful in more realistic problems, like velocity-selective transitionsin multilevel atomic systems, where the calculations on CPU for different group velocitiesand laser frequencies can lead several days.

1

88

APÊNDICE 7: RESUMO DA APRESENTAÇÃO PARA O GRUPO DE PES-

QUISA ESTRUTURA DA MATÉRIA E FÍSICA COMPUTACIONAL

ESTRUTURA DA MATÉRIA E FÍSICA

COMPUTACIONAL

Resumo: As equações de Bloch descrevem a interação da matriz densidade com um

campo eletromagnético ao longo do tempo. Abordamos neste trabalho a solução

dessas equações para um sistema atômico de dois níveis interagindo com um trem de

pulsos de laser ultracurtos. Utilizamos o método Runge-Kutta de 4ª ordem para

solução do sistema de equações. Adotamos parâmetros compatíveis com vapor

atômico de rubídio. Como nos interessa o deslocamento Doppler, efetuamos a

distribuição Maxwell-Boltzmann das velocidades. Para um perfil Doppler adequado

do vapor atômico de rubídio a faixa de velocidades calculadas vai de -600 a 600 m/s.

A solução computacional se torna custosa e demorada para um programa sequencial

comum, mas tem uma natureza obviamente paralelizável. O uso de unidades de

processamento gráfico (GPUs) para problemas computacionais paralelizáveis tem se

difundido nos últimos anos nas mais diversas áreas da ciência, como por exemplo em

problemas físicos envolvendo simulações de Monte Carlo. Realizamos testes em

placas NVIDIA, usando a plataforma CUDA em linguagem C. Comparamos o

desempenho em três processadores (CPUs) e quatro GPUs distintas para estabelecer

uma diferença entre os métodos e o ganho de desempenho ao se utilizar a paralelização

na GPU. Identificamos uma melhora máxima de 980x no tempo de execução na

comparação entre uma placa GTX 960 Ti e um processador Intel i5 4460. A melhora

no tempo se estabelece, em ordens menores, mesmo se utilizando uma placa de baixo

custo como a GT 210 em comparação a um processador intermediário como o i5 4460.

27 de abril de 2016, quarta-feira, 10 h

Laboratório Didático de Física e Química do

Departamento de Física de Ji-Paraná - UNIR

Seminário de Grupo

Teo Victor Resende da Silva

Departamento de Física - UNIR

Solução das equações de Bloch para

sistemas atômicos de dois níveis via GPUs

89

ANEXO 1: ACEITAÇÃO ENF 2016

15/06/2016 ENF2016

https://sec.sbfisica.org.br/eventos/enf/2016/sys/comprovantefinal_pt.asp?traId=1&aut=235156 1/1

Encontro de Física 2016 03 a 07 de setembro de 2016, Natal, RN

Declaração

Declaramos que o trabalho Density matrix calculations of Doppler­broadened atomic systemsimplemented on GPUs de autoria de Teo Victor Resende da Silva, Marco P. M. de Souza foiaceito para apresentação no(a) Encontro de Física 2016 no período de 03 a 07 de setembro de 2016,Natal, RN.

Apresentador: Marco P. M. de Souza (Universidade Federal de Rondônia (UNIR))Inscrição/Trabalho: 146/1

A forma de apresentação será informada em breve. São Paulo, 15 de junho de 2016

Comitê OrganizadorENF2016

90

ANEXO 2: CÓDIGO FONTE CUDA-C PARA A SOLUÇÃO PARA SISTE-

MAS DE TRÊS NÍVEIS TIPO Λ NA GPU

1 #include "cuda_runtime.h"

2 #include "device_launch_parameters.h"

3 #include "math.h"

4

5 #include <stdio.h>

6 #include <iostream >

7 #include <time.h>

8 #include "cuComplex.h"

9

10 // Desenvolvido por Marco Polo Moreno de Souza em 01/06/2017

11

12 #define Pi 3.141592653589793

13

14 #define blocks 100

15 #define threads 128

16

17 #define varredura 36

18

19 #define q33 (2*Pi*5e6)

20 #define q13 (0.5* q33)

21 #define q12 0

22 #define phi 0

23

24 #define fr0 100e6 //Taxa de repeticao (SI)

25 #define Tp 100e-15 // Largura de temporal do fento (SI)

26 #define Pulsos 100

27

28 #define PontosFemto 10

29 #define Passo 5 //em unidades de Hz

30

31 #define Omega (0.2* q33/(fr0*Tp))

32

33 #define w1 0

34 #define w2 (2*Pi *6800e6)

35 #define w3 (2*Pi*384 e12)

36 #define w (2*Pi*384 e12)

37 #define d 0

38

39 #define CUDA_ERROR_CHECK

40 #define CudaCheckError () __cudaCheckError(__FILE__ , __LINE__)

41

42 inline void __cudaCheckError(const char *file , const int line)

43

44 #ifdef CUDA_ERROR_CHECK

91

45 cudaError err = cudaGetLastError ();

46 if (cudaSuccess != err)

47

48 fpr intf (stderr , "cudaCheckError () failed at %s:%i : %s\n",

49 file , line , cudaGetErrorString(err));

50 system("pause");

51 exit(-1);

52

53 #endif

54

55 return;

56

57

58 __device__ void f(double a11 , double a22 , double a33 ,

59 double a12 , double b12 , double a13 ,

60 double b13 , double a23 , double b23 ,

61 int j, double &saida , double alpha) // sistema de 3

niveis

62

63 if (j==1) saida = 2*Omega *(cos(alpha)*b13 -sin(alpha)*a13) +0.5* q33*a33

;

64 if (j==2) saida = 2*Omega *(cos(alpha)*b23 -sin(alpha)*a23) +0.5* q33*a33

;

65 if (j==3) saida = 2*Omega *(sin(alpha)*(a13+a23)-cos(alpha)*(b13+b23)) -q33*a33

;

66

67 if (j==4) saida = -(w2-w1)*b12+Omega*(cos(alpha)*(b13+b23)-sin(alpha)*(a13+a23))-a12*

q12;

68 if (j==5) saida = (w2-w1)*a12+Omega*(cos(alpha)*(a23 -a13)+sin(alpha)*(b23 -b13))-b12*

q12;

69

70 if (j==6) saida = -(d-w1)*b13+Omega*cos(alpha)*b12+Omega*sin(alpha)*(a12+a11 -a33)-

a13*q13;

71 if (j==7) saida = (d-w1)*a13+Omega*sin(alpha)*b12+Omega*cos(alpha)*(a33 -a11 -a12)-

b13*q13;

72 if (j==8) saida = -(d-w2)*b23 -Omega*cos(alpha)*b12+Omega*sin(alpha)*(a12+a22 -a33)-

a23*q13;

73 if (j==9) saida = (d-w2)*a23 -Omega*sin(alpha)*b12+Omega*cos(alpha)*(a33 -a22 -a12)-

b23*q13;

74

75

76 __global__ void Kernel(double *a11 , double *a22 , double *a33 , double *a12 , double *b12 ,

double *a13 , double *b13 , double *a23 , double *b23 , int *jj)

77

78 // Paralelizacao na taxa de repeticao (variavel fr)

79

80 const int nucleos = blocks*threads;

81 int n,j,k,N,g;

82 double teste;

92

83 double k11_1 ,k11_2 ,k11_3 ,k11_4;

84 double k22_1 ,k22_2 ,k22_3 ,k22_4;

85 double k33_1 ,k33_2 ,k33_3 ,k33_4;

86 double ka12_1 ,ka12_2 ,ka12_3 ,ka12_4;

87 double kb12_1 ,kb12_2 ,kb12_3 ,kb12_4;

88 double ka13_1 ,ka13_2 ,ka13_3 ,ka13_4;

89 double kb13_1 ,kb13_2 ,kb13_3 ,kb13_4;

90 double ka23_1 ,ka23_2 ,ka23_3 ,ka23_4;

91 double kb23_1 ,kb23_2 ,kb23_3 ,kb23_4;

92 double c11 ,c22 ,c33;

93 double c12 ,c13 ,c23;

94 double d12 ,d13 ,d23;

95 double x1,x2,x3,z1 ,z2;

96 double h,t,Tr,fr,alpha;

97

98 int i = blockDim.x * blockIdx.x + threadIdx.x;

99

100 fr = fr0 + (i + nucleos*jj[0])*Passo;

101

102 t = 0;

103 N = -1;

104 Tr = 1/fr;

105 g = PontosFemto;

106 h = Tp/g;

107 //d = w3 - w;

108

109 c11 = c22 = c33 = 0;

110 c12 = c13 = c23 = 0;

111 d12 = d13 = d23 = 0;

112

113

114 for (n=1; n<=2* Pulsos +1; n++) //loop pulsos

115

116 if (n % 2 == 0)

117

118 N = N + 1;

119

120 alpha = -N*w*Tr + N*phi;

121

122 for (k=1; k<=g; k++) //loop tempo

123

124 t = t + h;

125

126 for (j=1; j<=9; j++)

127

128 f(a11[i],a22[i],a33[i],a12[i],b12[i],a13[i],b13[i

],a23[i],b23[i],j,teste ,alpha);

129

130 if (j==1) k11_1=teste; if (j==2) k22_1=teste;

93

if (j==3) k33_1=teste;

131 if (j==4) ka12_1=teste; if (j==5) kb12_1=teste;

if (j==6) ka13_1=teste;

132 if (j==7) kb13_1=teste; if (j==8) ka23_1=teste;

if (j==9) kb23_1=teste;

133

134

135 for (j=1; j<=9; j++)

136

137 f(a11[i]+ k11_1*h/2,a22[i]+ k22_1*h/2,a33[i]+k33_1*

h/2,a12[i]+ ka12_1*h/2,b12[i]+ kb12_1*h/2,a13[i

]+ ka13_1*h/2,b13[i]+ kb13_1*h/2,

138 a23

[

i

]+

ka23_1

*

h

/2,

b23

[

i

]+

kb23_1

*

h

/2,

j

,

teste

,

alpha

)

;

139 if (j==1) k11_2=teste; if (j==2) k22_2=teste;

if (j==3) k33_2=teste;

140 if (j==4) ka12_2=teste; if (j==5) kb12_2=teste;

if (j==6) ka13_2=teste;

141 if (j==7) kb13_2=teste; if (j==8) ka23_2=teste;

if (j==9) kb23_2=teste;

142

143

144 for (j=1; j<=9; j++)

145

146 f(a11[i]+ k11_2*h/2,a22[i]+ k22_2*h/2,a33[i]+k33_2*

h/2,a12[i]+ ka12_2*h/2,b12[i]+ kb12_2*h/2,a13[i

]+ ka13_2*h/2,b13[i]+ kb13_2*h/2,

94

147 a23

[

i

]+

ka23_2

*

h

/2,

b23

[

i

]+

kb23_2

*

h

/2,

j

,

teste

,

alpha

)

;

148 if (j==1) k11_3=teste; if (j==2) k22_3=teste;

if (j==3) k33_3=teste;

149 if (j==4) ka12_3=teste; if (j==5) kb12_3=teste;

if (j==6) ka13_3=teste;

150 if (j==7) kb13_3=teste; if (j==8) ka23_3=teste;

if (j==9) kb23_3=teste;

151

152

153 for (j=1; j<=9; j++)

154

155 f(a11[i]+ k11_3*h,a22[i]+k22_3*h,a33[i]+k33_3*h,

a12[i]+ ka12_3*h,b12[i]+ kb12_3*h,a13[i]+ ka13_3

*h,b13[i]+ kb13_3*h,

156 a23

[

i

]+

ka23_3

*

h

,

b23

[

i

]+

95

kb23_3

*

h

,

j

,

teste

,

alpha

)

;

157 if (j==1) k11_4=teste; if (j==2) k22_4=teste;

if (j==3) k33_4=teste;

158 if (j==4) ka12_4=teste; if (j==5) kb12_4=teste;

if (j==6) ka13_4=teste;

159 if (j==7) kb13_4=teste; if (j==8) ka23_4=teste;

if (j==9) kb23_4=teste;

160

161

162 a11[i] = a11[i] + h*( k11_1 /6+ k11_2 /3+ k11_3 /3+ k11_4 /6)

; a22[i] = a22[i] + h*( k22_1 /6+ k22_2 /3+ k22_3 /3+

k22_4 /6);

163 a33[i] = a33[i] + h*( k33_1 /6+ k33_2 /3+ k33_3 /3+ k33_4 /6)

;

164 a12[i] = a12[i] + h*( ka12_1 /6+ ka12_2 /3+ ka12_3 /3+ ka12_4 /6)

; b12[i] = b12[i] + h*( kb12_1 /6+ kb12_2 /3+ kb12_3 /3+

kb12_4 /6);

165 a13[i] = a13[i] + h*( ka13_1 /6+ ka13_2 /3+ ka13_3 /3+ ka13_4 /6)

; b13[i] = b13[i] + h*( kb13_1 /6+ kb13_2 /3+ kb13_3 /3+

kb13_4 /6);

166 a23[i] = a23[i] + h*( ka23_1 /6+ ka23_2 /3+ ka23_3 /3+ ka23_4 /6)

; b23[i] = b23[i] + h*( kb23_1 /6+ kb23_2 /3+ kb23_3 /3+

kb23_4 /6);

167

168 //loop tempo

169

170

171

172 if (n % 2 == 1)

173

174 t = t + (Tr-Tp);

175 x1 = (w2-w1)*(Tr-Tp);

176 x2 = (d -w1)*(Tr -Tp);

177 x3 = (d -w2)*(Tr -Tp);

178 z1 = q33*(Tr-Tp);

179 z2 = q12*(Tr-Tp);

180

181 c11 = a11[i] + 0.5* a33[i]*(1-exp(-z1));

96

182 c22 = a22[i] + 0.5* a33[i]*(1-exp(-z1));

183 c33 = a33[i]*exp(-z1);

184 c12 = (a12[i]*cos(x1)-b12[i]*sin(x1))*exp(-z2);

185 d12 = (a12[i]*sin(x1)+b12[i]*cos(x1))*exp(-z2);

186 c13 = (a13[i]*cos(x2)-b13[i]*sin(x2))*exp( -0.5*z1);

187 d13 = (a13[i]*sin(x2)+b13[i]*cos(x2))*exp( -0.5*z1);

188 c23 = (a23[i]*cos(x3)-b23[i]*sin(x3))*exp( -0.5*z1);

189 d23 = (a23[i]*sin(x3)+b23[i]*cos(x3))*exp( -0.5*z1);

190

191 a11[i] = c11; a22[i] = c22; a33[i] = c33;

192 a12[i] = c12; a13[i] = c13; a23[i] = c23;

193 b12[i] = d12; b13[i] = d13; b23[i] = d23;

194

195

196 //loop pulsos

197

198

199

200 int main()

201

202 clock_t begin , end;

203 double time_spent;

204 begin = clock();

205

206 FILE *arquivo;

207 arquivo=fopen("dados.dat","w");

208 const int nucleos = blocks*threads;

209

210 cudaDeviceProp prop;

211 int count;

212

213 cudaGetDeviceCount (&count);

214 for (int s=0;s<count;s++)

215

216 cudaGetDeviceProperties (&prop ,s);

217 printf ("General information\n");

218 printf ("%s", prop.name);

219 printf (", Compute Capability %d.%d\n", prop.major , prop.minor);

220 printf ("Clock rate: %d MHz\n", int(prop.clockRate /1000));

221 printf ("Kernel execition timeout: ");

222 if (prop.kernelExecTimeoutEnabled) printf ("Enabled\n");

223 else printf ("

Disabled\n

");

224 printf ("Max threads per block: %d\n", prop.maxThreadsPerBlock);

225 printf ("Max thread dimensions: (%d, %d, %d)\n", prop.maxThreadsDim [0],

prop.maxThreadsDim [1], prop.maxThreadsDim [2]);

226 printf ("Max grid dimensions: (%d, %d)\n", prop.maxGridSize [1], prop.

maxGridSize [2]);

97

227 printf ("Multiprocessor count: %d\n", prop.multiProcessorCount);

228 printf ("Shared memory per MP: %ld kb\n", prop.sharedMemPerBlock /1024);

229 printf ("Registers per MP: %d\n", prop.regsPerBlock);

230 printf ("Warp size: %ld\n\n", prop.warpSize);

231 // printf ("Total Global Memory: %d\n\n", prop.totalGlobalMem);

232

233

234 printf ("Blocks = %d\n", blocks);

235 printf ("Threads = %d\n\n", threads);

236

237 printf ("Calculando ...\n");

238

239 double a11[nucleos ]; double a22[nucleos ];

240 double a33[nucleos ];

241 double a12[nucleos ]; double b12[nucleos ];

242 double a23[nucleos ]; double b23[nucleos ];

243 double a13[nucleos ]; double b13[nucleos ];

244 int jj[1];

245 double soma ,dfr;

246

247 double *dev_a11; double *dev_a22;

248 double *dev_a33;

249 double *dev_a12; double *dev_b12;

250 double *dev_a13; double *dev_b13;

251 double *dev_a23; double *dev_b23;

252 int *dev_jj;

253

254 cudaMalloc((void **)&dev_a11 , nucleos * sizeof(double)); cudaMalloc((void **)&

dev_a22 , nucleos * sizeof(double));

255 cudaMalloc((void **)&dev_a33 , nucleos * sizeof(double));

256 cudaMalloc((void **)&dev_a12 , nucleos * sizeof(double)); cudaMalloc((void **)&

dev_b12 , nucleos * sizeof(double));

257 cudaMalloc((void **)&dev_a23 , nucleos * sizeof(double)); cudaMalloc((void **)&

dev_b23 , nucleos * sizeof(double));

258 cudaMalloc((void **)&dev_a13 , nucleos * sizeof(double)); cudaMalloc((void **)&

dev_b13 , nucleos * sizeof(double));

259 cudaMalloc((void **)&dev_jj , 1 * sizeof(int));

260

261 fpr intf (arquivo , "fr rho11 rho22 rho33 sigma12\n");

262 for (int pp=-varredura; pp <=varredura -1; pp++)

263

264 jj[0] = pp;

265

266 for (int q=0;q<=nucleos -1;q++)

267

268 a11[q] = 0.5; a22[q] = 0.5;

269 a33[q] = 0;

270 a12[q] = 0; b12[q] = 0;

271 a13[q] = 0; b13[q] = 0;

98

272 a23[q] = 0; b23[q] = 0;

273

274

275 cudaMemcpy(dev_a11 , a11 , nucleos * sizeof(double), cudaMemcpyHostToDevice

); cudaMemcpy(dev_a22 , a22 , nucleos * sizeof(double),

cudaMemcpyHostToDevice);

276 cudaMemcpy(dev_a33 , a33 , nucleos * sizeof(double), cudaMemcpyHostToDevice

);

277 cudaMemcpy(dev_a12 , a12 , nucleos * sizeof(double), cudaMemcpyHostToDevice

); cudaMemcpy(dev_b12 , b12 , nucleos * sizeof(double),

cudaMemcpyHostToDevice);

278 cudaMemcpy(dev_a23 , a23 , nucleos * sizeof(double), cudaMemcpyHostToDevice

); cudaMemcpy(dev_b23 , b23 , nucleos * sizeof(double),

cudaMemcpyHostToDevice);

279 cudaMemcpy(dev_a13 , a13 , nucleos * sizeof(double), cudaMemcpyHostToDevice

); cudaMemcpy(dev_b13 , b13 , nucleos * sizeof(double),

cudaMemcpyHostToDevice);

280 cudaMemcpy(dev_jj , jj, 1 * sizeof(int), cudaMemcpyHostToDevice);

281

282 Kernel <<<blocks ,threads >>>(dev_a11 , dev_a22 , dev_a33 , dev_a12 , dev_b12 ,

dev_a13 , dev_b13 , dev_a23 , dev_b23 , dev_jj);

283 CudaCheckError ();

284

285 // cudaDeviceSynchronize waits for the kernel to finish , and returns

286 // any errors encountered during the launch.

287 cudaDeviceSynchronize ();

288

289 cudaMemcpy(a11 , dev_a11 , nucleos * sizeof(double), cudaMemcpyDeviceToHost

); cudaMemcpy(a22 , dev_a22 , nucleos * sizeof(double),

cudaMemcpyDeviceToHost);

290 cudaMemcpy(a33 , dev_a33 , nucleos * sizeof(double), cudaMemcpyDeviceToHost

);

291 cudaMemcpy(a12 , dev_a12 , nucleos * sizeof(double), cudaMemcpyDeviceToHost

); cudaMemcpy(b12 , dev_b12 , nucleos * sizeof(double),

cudaMemcpyDeviceToHost);

292 cudaMemcpy(a13 , dev_a13 , nucleos * sizeof(double), cudaMemcpyDeviceToHost

); cudaMemcpy(b13 , dev_b13 , nucleos * sizeof(double),

cudaMemcpyDeviceToHost);

293 cudaMemcpy(a23 , dev_a23 , nucleos * sizeof(double), cudaMemcpyDeviceToHost

); cudaMemcpy(b23 , dev_b23 , nucleos * sizeof(double),

cudaMemcpyDeviceToHost);

294

295 printf ("*%d ", jj[0]);

296 for (int q=0; q<=nucleos -1; q++)

297

298 dfr = (q + jj[0]* nucleos)*Passo;

299 soma = a11[q] + a22[q] + a33[q];

300 printf ( "%d %.12f %.12f %.12f %.12f\n", q, a11[q],

a22[q], a33[q], soma);

99

301 fpr intf (arquivo , "%.12f %.12f %.12f %.12f %.12f\n", dfr , a11[q],

a22[q], a33[q], sqrt(a12[q]*a12[q]+b12[q]*b12[q]));

302

303

304

305 cudaFree(dev_a11);cudaFree(dev_a22);

306 cudaFree(dev_a33);

307 cudaFree(dev_a12);cudaFree(dev_b12);

308 cudaFree(dev_a13);cudaFree(dev_b13);

309 cudaFree(dev_a23);cudaFree(dev_b23);

310 cudaFree(dev_jj);

311

312 // cudaDeviceReset must be called before exiting in order for profiling and

313 // tracing tools such as Nsight and Visual Profiler to show complete traces.

314 cudaDeviceReset();

315

316 end = clock();

317 time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

318 if (time_spent <=60) printf ("\nTempo de execucao = %f s\n\n", time_spent);

319 if (time_spent > 60 && time_spent <= 3600) printf ("\nTempo de execucao = %f min\n\n

", time_spent /60);

320 if (time_spent >3600) printf ("\nTempo de execucao = %f h\n\n", time_spent /3600);

321

322 printf ("\a");

323 system ("pause");

324 fc lose (arquivo);

325

100

ANEXO 3: CÓDIGO FONTE C++ PARA A SOLUÇÃO PARA SISTEMAS

DE TRÊS NÍVEIS TIPO Λ NA CPU

1 #include <stdio.h>

2 #include <math.h>

3 #include <time.h>

4 #include <iostream >

5

6 //31 -05 -2010

7 // Reescrito em 25/03/2017

8 // calculos numericos na presenca do campo

9 // calculos analiticos no decaimento

10 //Plota Populacoes e coerencias vs fr

11 // Efeito apos passagem de apenas N pulsos

12 //Para sistemas em lambda

13

14 const double Pi = 3.141592654;

15

16 const double q33 = (2*Pi)*5e6;

17 const double q13 = 0.5* q33;

18 const double q12 = 0;

19 const double phi = 0;

20

21 const double fr0 = 100e6; //Taxa de repeticao (SI)

22 const double Tp = 100e-15; // Largura de temporal do fento (SI)

23 const double Omega = 0.2* q33/(fr0*Tp);

24 const int Pulsos = 100;

25

26 const double PassoFemto = 10;

27 const double Passo = 5; //em unidades de Hz

28 const int Varredura = 450000; //em unidades do Passo

29

30 const double w1 = 0;

31 const double w2 = 2*Pi*6800e6;

32 const double w3 = 2*Pi*384 e12;

33 const double w = 2*Pi*384 e12;

34

35 double x1,x2,x3,z1 ,z2,saida;//soma ,

36 double d,h,t;

37 double Tr,fr,a10 ,a20 ,a30 ,alpha;

38 int n,j,k,g,N,p;

39

40 double a11 ,a22 ,a33 ,a12 ,b12 ,a13 ,b13 ,a23 ,b23;

41 double c11 ,c22 ,c33 ,c12 ,c13 ,c23 ,d12 ,d13 ,d23;

42 double k11_1 ,k11_2 ,k11_3 ,k11_4;

43 double k22_1 ,k22_2 ,k22_3 ,k22_4;

44 double k33_1 ,k33_2 ,k33_3 ,k33_4;

101

45 double ka12_1 ,ka12_2 ,ka12_3 ,ka12_4;

46 double kb12_1 ,kb12_2 ,kb12_3 ,kb12_4;

47 double ka13_1 ,ka13_2 ,ka13_3 ,ka13_4;

48 double kb13_1 ,kb13_2 ,kb13_3 ,kb13_4;

49 double ka23_1 ,ka23_2 ,ka23_3 ,ka23_4;

50 double kb23_1 ,kb23_2 ,kb23_3 ,kb23_4;

51

52 void f(double a11 ,double a22 ,double a33 ,

53 double a12 ,double b12 ,double a13 ,

54 double b13 ,double a23 ,double b23 ,int i) // sistema Lambda

55

56 if (i==1) saida = 2*Omega *(cos(alpha)*b13 -sin(alpha)*a13) +0.5* q33*a33

;

57 if (i==2) saida = 2*Omega *(cos(alpha)*b23 -sin(alpha)*a23) +0.5* q33*a33

;

58 if (i==3) saida = 2*Omega *(sin(alpha)*(a13+a23)-cos(alpha)*(b13+b23)) -q33*a33

;

59

60 if (i==4) saida = -(w2-w1)*b12+Omega*(cos(alpha)*(b13+b23)-sin(alpha)*(a13+a23))-a12*

q12;

61 if (i==5) saida = (w2-w1)*a12+Omega*(cos(alpha)*(a23 -a13)+sin(alpha)*(b23 -b13))-b12*

q12;

62

63 if (i==6) saida = -(d-w1)*b13+Omega*cos(alpha)*b12+Omega*sin(alpha)*(a12+a11 -a33)

-0.5*a13*q33;

64 if (i==7) saida = (d-w1)*a13+Omega*sin(alpha)*b12+Omega*cos(alpha)*(a33 -a11 -a12)

-0.5*b13*q33;

65 if (i==8) saida = -(d-w2)*b23 -Omega*cos(alpha)*b12+Omega*sin(alpha)*(a12+a22 -a33)

-0.5*a23*q33;

66 if (i==9) saida = (d-w2)*a23 -Omega*sin(alpha)*b12+Omega*cos(alpha)*(a33 -a22 -a12)

-0.5*b23*q33;

67

68

69 main()

70

71 clock_t begin , end;

72 double time_spent;

73 begin = clock();

74

75 FILE *arquivo;

76 arquivo=fopen("dados.dat","w");

77

78 fpr intf (arquivo , "tempo rho11 rho22 rho33 sigma12\n");

79

80 a10 = 0.5; // populacao inicial do estado 1

81 a20 = 0.5; // populacao inicial do estado 2

82 a30 = 0; // populacao inicial do estado 3

83

84 a11 = a10; a22 = a20; a33 = a30;

102

85 a12 = 0; b12 = 0; a13 = 0;

86 b13 = 0; a23 = 0; b23 = 0;

87

88 d = w3 - w;

89

90 for (p=-Varredura; p<= Varredura; p++)

91

92 t = 0;

93 N = -1;

94 fr = fr0 + p*Passo;

95 Tr = 1/fr;

96

97 for (n=1; n<=2* Pulsos +1; n++)

98

99 // printf ("*");

100 if (n % 2 == 0)

101

102 N = N + 1;

103 g = PassoFemto;

104 h = (1/ double(g))*Tp;

105

106 alpha = -N*w*Tr + N*phi;

107

108 for (k=1; k<=g; k++)

109

110 t = t + h;

111

112 for (j=1;j<=9;j++)

113

114 f(a11 ,a22 ,a33 ,a12 ,b12 ,a13 ,b13 ,a23 ,b23 ,j);

115

116 if (j==1) k11_1=saida; if (j==2) k22_1=

saida; if (j==3) k33_1=saida;

117 if (j==4) ka12_1=saida; if (j==5) kb12_1=

saida; if (j==6) ka13_1=saida; if (j

==7) kb13_1=saida;

118 if (j==8) ka23_1=saida; if (j==9) kb23_1=

saida;

119

120

121 for (j=1;j<=9;j++)

122

123 f(a11+k11_1*h/2,a22+k22_1*h/2,a33+k33_1*h

/2,a12+ka12_1*h/2,b12+kb12_1*h/2,a13+

ka13_1*h/2,b13+kb13_1*h/2,

124 a23

+

ka23_1

*

103

h

/2,

b23

+

kb23_1

*

h

/2,

j

)

;

125 if (j==1) k11_2=saida; if (j==2) k22_2=

saida; if (j==3) k33_2=saida;

126 if (j==4) ka12_2=saida; if (j==5) kb12_2=

saida; if (j==6) ka13_2=saida; if (j

==7) kb13_2=saida;

127 if (j==8) ka23_2=saida; if (j==9) kb23_2=

saida;

128

129

130 for (j=1;j<=9;j++)

131

132 f(a11+k11_2*h/2,a22+k22_2*h/2,a33+k33_2*h

/2,a12+ka12_2*h/2,b12+kb12_2*h/2,a13+

ka13_2*h/2,b13+kb13_2*h/2,

133 a23+

ka23_2

*

h

/2,

b23

+

kb23_2

*

h

/2,

j

)

;

134 if (j==1) k11_3=saida; if (j==2) k22_3=

saida; if (j==3) k33_3=saida;

135 if (j==4) ka12_3=saida; if (j==5) kb12_3=

saida; if (j==6) ka13_3=saida; if (j

==7) kb13_3=saida;

136 if (j==8) ka23_3=saida; if (j==9) kb23_3=

saida;

137

138

104

139 for (j=1;j<=9;j++)

140

141 f(a11+k11_3*h,a22+k22_3*h,a33+k33_3*h,a12

+ka12_3*h,b12+kb12_3*h,a13+ka13_3*h,

b13+kb13_3*h,

142 a23+

ka23_3

*

h

,

b23

+

kb23_3

*

h

,

j

)

;

143 if (j==1) k11_4=saida; if (j==2) k22_4=

saida; if (j==3) k33_4=saida;

144 if (j==4) ka12_4=saida; if (j==5) kb12_4=

saida; if (j==6) ka13_4=saida; if (j

==7) kb13_4=saida;

145 if (j==8) ka23_4=saida; if (j==9) kb23_4=

saida;

146

147

148 a11 = a11 + h*( k11_1 /6+ k11_2 /3+ k11_3 /3+ k11_4

/6); a22 = a22 + h*( k22_1 /6+ k22_2 /3+ k22_3

/3+ k22_4 /6);

149 a33 = a33 + h*( k33_1 /6+ k33_2 /3+ k33_3 /3+ k33_4

/6);

150 a12 = a12 + h*( ka12_1 /6+ ka12_2 /3+ ka12_3 /3+ ka12_4

/6); b12 = b12 + h*( kb12_1 /6+ kb12_2 /3+ kb12_3

/3+ kb12_4 /6);

151 a13 = a13 + h*( ka13_1 /6+ ka13_2 /3+ ka13_3 /3+ ka13_4

/6); b13 = b13 + h*( kb13_1 /6+ kb13_2 /3+ kb13_3

/3+ kb13_4 /6);

152 a23 = a23 + h*( ka23_1 /6+ ka23_2 /3+ ka23_3 /3+ ka23_4

/6); b23 = b23 + h*( kb23_1 /6+ kb23_2 /3+ kb23_3

/3+ kb23_4 /6);

153

154

155

156 if (n % 2 == 1)

157

158 t = t + (Tr-Tp);

159 x1 = (w2-w1)*(Tr-Tp);

105

160 x2 = (d -w1)*(Tr -Tp);

161 x3 = (d -w2)*(Tr -Tp);

162 z1 = q33*(Tr-Tp);

163 z2 = q12*(Tr-Tp);

164

165 c11 = a11 + 0.5* a33*(1-exp(-z1));

166 c22 = a22 + 0.5* a33*(1-exp(-z1));

167 c33 = a33*exp(-z1);

168 c12 = (a12*cos(x1)-b12*sin(x1))*exp(-z2);

169 d12 = (a12*sin(x1)+b12*cos(x1))*exp(-z2);

170 c13 = (a13*cos(x2)-b13*sin(x2))*exp(-0.5*z1);

171 d13 = (a13*sin(x2)+b13*cos(x2))*exp(-0.5*z1);

172 c23 = (a23*cos(x3)-b23*sin(x3))*exp(-0.5*z1);

173 d23 = (a23*sin(x3)+b23*cos(x3))*exp(-0.5*z1);

174

175 a11 = c11; a22 = c22; a33 = c33;

176 a12 = c12; a13 = c13; a23 = c23;

177 b12 = d12; b13 = d13; b23 = d23;

178

179

180

181 fpr intf (arquivo ,"%12.10f %12.10f %12.10f %12.10f %12.10f %12.10f %12.10f

%12.10f %12.10f %12.10f %12.10f %12.10f %12.10f %12.10f %12.10f\n",

182 p*Passo ,a11 ,a22 ,a33 ,sqrt(a12*a12+b12*b12),sqrt(a13*a13+b13*b13),

183 sqrt(a23*a23+b23*b23) ,0.5*a11 +0.5* a22+a12 ,0.5* a11 +0.5*a22 -a12 ,a12 ,b12 ,a13 ,

b13 ,a23 ,b23);

184

185 a11 = a10; a22 = a20; a33 = a30;

186 a12 = 0; b12 = 0; a13 = 0;

187 b13 = 0; a23 = 0; b23 = 0;

188

189

190 fc lose (arquivo);

191 printf ("\a");

192

193 end = clock();

194 time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

195 if (time_spent <=60) printf ("\nTempo de execucao = %f s\n\n", time_spent);

196 if (time_spent > 60 && time_spent <= 3600) printf ("\nTempo de execucao = %f min\n\n

", time_spent /60);

197 if (time_spent >3600) printf ("\nTempo de execucao = %f h\n\n", time_spent /3600);

198